Browser / API Request Debugging workflow

Why API Sorting and Filtering Parameters Disagree

Debug list APIs where sort, filter, search and pagination parameters produce unexpected results because client and server interpret query values differently.

Quick Answer

Sorting and filtering bugs often come from mismatched parameter names, repeated parameter formats, URL encoding, default sort order, type coercion or filters that are applied before or after pagination differently than the client expects. Compare the final request URL with the server query contract.

Example Scenario

A table shows active users sorted by created date, but the backend returns inactive users first or ignores the sort. The UI state looks right. The final request contains sort=createdAt:desc while the API expects sort=-created_at, and status filters are sent as status[]=active while the server expects repeated status=active values.

Step-by-Step Explanation

  1. Capture the final URL after UI state is serialized.
  2. Compare parameter names and formats with API documentation.
  3. Check whether arrays use repeated keys, brackets, commas or JSON encoding.
  4. Verify sort field names, direction syntax and default sort behavior.
  5. Confirm whether filters apply before pagination.
  6. Log parsed server-side query parameters for one failing request.

The UI State Is Not the Request

A table component can show the correct selected filters while the request URL contains a different representation. The bug often lives in the serializer that converts UI state into query parameters. Always inspect the final URL or request object, not only the component state.

Small naming differences matter. A frontend may use createdAt while the API expects created_at. A direction may be desc in one API and -field in another. A filter may be named status in the UI and state in the backend.

Capture one failing URL and decode each parameter. That gives everyone a concrete object to compare against the contract.

Array Parameters Need Agreement

Multi-select filters can be represented as status=active&status=pending, status[]=active&status[]=pending, status=active,pending or a JSON-encoded array. Each format can be valid in some API, but the client and server must agree.

When the server receives only one selected value, check whether its query parser keeps the last repeated value or turns repeats into an array. When it receives one comma-separated string, check whether the API expects splitting.

Document the array format beside the endpoint. Otherwise every new filter repeats the same argument.

Types Change Filter Semantics

Query parameters are text at the transport boundary. The server decides whether active=true becomes a boolean, the string "true" or an invalid value. Numeric filters, dates and null-like values need explicit parsing rules.

A common bug is sending empty strings for optional filters. The client thinks the filter is absent, while the server treats empty string as a real filter value. Another bug is sending false and then dropping it because the serializer skips falsy values.

Test true, false, zero, empty string and missing value separately. They often produce different query behavior.

Default Sort Can Hide Missing Sort

If a sort parameter is malformed or ignored, the server may fall back to a default order. That can look like the API sorted incorrectly when it actually did not apply the requested sort at all.

Log parsed sort field and direction server-side. If the parser rejects a field, return a clear validation error rather than silently falling back when the endpoint is used for interactive tables.

Stable sorting matters for pagination. If the default sort is unstable, pages can shift even when filters are correct.

Filter Order Versus Pagination Order

Most clients expect filtering to happen before pagination. If a server paginates first and filters afterward, pages can have fewer items than expected and later pages may contain records that should have appeared earlier.

This mistake often appears in custom in-memory filtering or proxy layers that fetch one page from an upstream API and then apply additional filters locally. The visible result looks filtered, but the pagination metadata no longer matches.

Check total count, page size and item count together. If filtered pages have inconsistent lengths, inspect where the filter is applied.

Evidence to Keep

Save UI state, final URL, decoded query object, server parsed query and response summary for one failing case. That chain shows exactly where the disagreement begins.

Use URL Encoder/Decoder to inspect query values and Text Diff Checker to compare working and failing URLs. For response differences, use JSON Compare after removing volatile metadata.

Add regression tests for each supported filter type and sort field. Include at least one multi-select filter, one false boolean, one zero numeric value and one date range.

Return validation errors for unknown sort fields and unsupported filters. Silent ignore behavior feels convenient at first, but it makes debugging harder because the UI appears to send a valid request that the API quietly discards.

Document defaults explicitly. If no sort is provided, clients should know the fallback order. If a filter is absent, clients should know whether that means all records or a server-defined subset.

Search parameters deserve the same treatment as filters. A search box may trim whitespace, collapse repeated spaces or normalize accents before sending the request. If the server does different normalization, users see results that do not match the UI text.

Date ranges need boundary rules. Clients and servers must agree whether end dates are inclusive, exclusive, local date based or UTC instant based. Many off-by-one-day bugs are actually filter contract bugs.

When debugging production reports, save both the human label and the raw parameter. A label such as Last 30 days is not enough; the backend needs the actual start and end values it received.

Sorting by derived fields also needs documentation. A UI label such as revenue may map to gross revenue, net revenue, converted currency or cached aggregate. If the server and client use different definitions, the sort appears wrong even when parameter syntax is correct.

For admin tools, expose the applied query summary beside results in non-production. Showing parsed filters, sort field and page size helps testers spot serialization bugs before they become customer reports.

If a filter depends on user permissions, compare results with two accounts. The same query parameters can legitimately return different data when row-level access rules apply. Without that context, a permission difference can be mistaken for a filtering bug.

For saved views, store the version of the query schema. A saved filter created before a field rename may continue sending old parameter names until it is migrated.

Code Examples

Do not drop false or zero filters
function setParam(params, key, value) {
  if (value === undefined || value === null || value === '') return;
  params.set(key, String(value));
}
Repeated parameter array format
const params = new URLSearchParams();
for (const status of ['active', 'pending']) {
  params.append('status', status);
}
Log parsed query on the server
console.log({
  rawQuery: request.url.split('?')[1] || '',
  parsed: Object.fromEntries(new URL(request.url).searchParams)
});

Common Mistakes

  • Assuming UI filter state matches the final request URL.
  • Using the wrong array parameter format.
  • Dropping false or zero because serializer checks truthiness.
  • Silently falling back when sort syntax is invalid.
  • Filtering after pagination and returning misleading page metadata.

FAQ

Why does my false filter disappear?

The serializer may skip falsy values. Check for null or undefined instead of truthiness.

Which array query format should I use?

Use the format documented by the API. Repeated keys, brackets and comma lists are not interchangeable.

Should invalid sort fields return an error?

For APIs used by tables, a clear validation error is often better than silently falling back.

Why are filtered pages short?

The server may be paginating before filtering or applying extra filters after fetching an upstream page.