FilteringQuery Params6 min read
Filtering
Most list endpoints accept query parameters to filter results server-side. This guide covers parameter types, combining filters, and building dynamic filter UIs in React.
Basic filtering
Append query parameters to any list endpoint URL. Multiple parameters are combined with AND logic — all conditions must match.
basic-filters.js
javascript
"color:#c4b5fd">const BASE_URL = "https:">//hotel-data.k3s.ahsm-krakow.com/api/v1";
"color:#6b7280">// Single filter: only enabled properties
"color:#c4b5fd">const properties = "color:#c4b5fd">await fetch(
"color:#86efac">`${BASE_URL}/properties?enabled=true`
).then((r) => r.json());
"color:#6b7280">// Multiple filters combined: suites with balconies at apt
"color:#c4b5fd">const roomTypes = "color:#c4b5fd">await fetch(
"color:#86efac">`${BASE_URL}/room-types?property_id=apt&category=suite&has_balcony=true`
).then((r) => r.json());
"color:#6b7280">// Boolean filters: hot tub + duplex + at least 40m2
"color:#c4b5fd">const luxuryRooms = "color:#c4b5fd">await fetch(
"color:#86efac">`${BASE_URL}/room-types?has_hot_tub=true&is_duplex=true&min_size=40`
).then((r) => r.json());Filtering issues and maintenance
issues-filters.js
javascript
"color:#6b7280">// Open high-priority issues in room 205
"color:#c4b5fd">const issues = "color:#c4b5fd">await fetch(
"color:#86efac">`${BASE_URL}/issues?status=open&priority=high&room_number=205&property_id=apt`
).then((r) => r.json());
"color:#6b7280">// All plumbing issues across all properties
"color:#c4b5fd">const plumbingIssues = "color:#c4b5fd">await fetch(
"color:#86efac">`${BASE_URL}/issues?category=plumbing`
).then((r) => r.json());
"color:#6b7280">// Overdue maintenance schedules
"color:#c4b5fd">const overdue = "color:#c4b5fd">await fetch(
"color:#86efac">`${BASE_URL}/maintenance/schedules?overdue=true`
).then((r) => r.json());Building query strings dynamically
Use URLSearchParams to construct query strings from objects. Skip undefined values to avoid sending empty parameters.
query-builder.ts
javascript
"color:#c4b5fd">function buildQueryString(params: Record<string, string | number | boolean | undefined>): string {
"color:#c4b5fd">const query = "color:#c4b5fd">new URLSearchParams();
for ("color:#c4b5fd">const [key, value] of Object.entries(params)) {
"color:#c4b5fd">if (value !== undefined && value !== null && value !== "") {
query.set(key, String(value));
}
}
"color:#c4b5fd">return query.toString();
}
"color:#6b7280">// Usage
"color:#c4b5fd">const filters = {
property_id: "apt",
category: "suite",
has_balcony: true,
min_size: 40,
active: undefined, "color:#6b7280">// skipped
};
"color:#c4b5fd">const qs = buildQueryString(filters);
"color:#6b7280">// → "property_id=apt&category=suite&has_balcony=true&min_size=40"
"color:#c4b5fd">const response = "color:#c4b5fd">await fetch("color:#86efac">`${BASE_URL}/room-types?${qs}`);Dynamic filter UI in React
Use a custom hook that re-fetches whenever filters change. Serialize the filter object to a stable string for the effect dependency.
useRoomTypes.ts
javascript
"color:#c4b5fd">import { useState, useEffect } "color:#c4b5fd">from "react";
"color:#c4b5fd">const BASE_URL = "https:">//hotel-data.k3s.ahsm-krakow.com/api/v1";
interface RoomTypeFilters {
property_id?: string;
category?: string;
has_hot_tub?: boolean;
has_balcony?: boolean;
min_size?: number;
max_guests?: number;
}
"color:#c4b5fd">function useRoomTypes(filters: RoomTypeFilters) {
"color:#c4b5fd">const [data, setData] = useState([]);
"color:#c4b5fd">const [loading, setLoading] = useState(false);
"color:#c4b5fd">const [error, setError] = useState<Error | null>(null);
useEffect(() => {
"color:#c4b5fd">const params = "color:#c4b5fd">new URLSearchParams();
Object.entries(filters).forEach(([k, v]) => {
"color:#c4b5fd">if (v !== undefined) params.set(k, String(v));
});
setLoading(true);
fetch("color:#86efac">`${BASE_URL}/room-types?${params}`)
.then((r) => r.json())
.then(({ data }) => setData(data))
."color:#c4b5fd">catch(setError)
.finally(() => setLoading(false));
}, [JSON.stringify(filters)]);
"color:#c4b5fd">return { data, loading, error };
}
"color:#6b7280">// Usage in a component
"color:#c4b5fd">function RoomTypePicker() {
"color:#c4b5fd">const [filters, setFilters] = useState<RoomTypeFilters>({
property_id: "apt",
active: true,
});
"color:#c4b5fd">const { data, loading } = useRoomTypes(filters);
"color:#c4b5fd">return (
<div>
<label>
<input
type="checkbox"
onChange={(e) =>
setFilters((f) => ({ ...f, has_hot_tub: e.target.checked || undefined }))
}
/>
Has hot tub
</label>
{/* render data... */}
</div>
);
}Common filter combinations
Reference table of useful filter combinations for common use cases.
| Goal | Endpoint | Parameters |
|---|---|---|
| All active room types at a property | /room-types | ?property_id=apt&active=true |
| Suites with hot tubs | /room-types | ?category=suite&has_hot_tub=true |
| Rooms for large groups (4+ guests) | /room-types | ?max_guests=4 |
| Duplex apartments larger than 60m2 | /room-types | ?is_duplex=true&min_size=60 |
| All rooms on floor 3 at apt | /rooms | ?property_id=apt&floor=3 |
| Rooms of a specific type | /rooms | ?room_type=apt-penthouse |
| Open critical issues at krw | /issues | ?property_id=krw&status=open&priority=critical |
| Overdue maintenance at apt | /maintenance/schedules | ?property_id=apt&overdue=true |
Parameter type reference
| Type | Accepted values | Example |
|---|---|---|
| string | Any string | property_id=apt |
| boolean | true / false | has_hot_tub=true |
| integer | Whole number | floor=3, min_size=40 |
| enum | One of a fixed set | status=open, priority=high |