Framework-agnostic server helpers for the HTTP QUERY method (RFC 10008). Validate incoming QUERY requests, enforce the RFC's Content-Type rule, negotiate accepted query formats, and advertise them with Accept-Query.
Built on Web-standard Request/Response, so it runs anywhere they do — Hono, Deno, Bun, Cloudflare Workers, and Node (via a web adapter). Its only dependency is @danmat/accept-query.
import { checkQueryRequest, readQueryJson, withAcceptQuery } from "@danmat/query-server";
const ACCEPTED = ["application/json", "application/sql"];
async function handler(request: Request): Promise<Response> {
// Reject non-QUERY, missing/unsupported Content-Type — with correct status codes.
const rejection = checkQueryRequest(request, { accept: ACCEPTED });
if (rejection) return withAcceptQuery(rejection, ACCEPTED);
const query = await readQueryJson<{ filter: unknown }>(request);
const results = await runQuery(query);
return withAcceptQuery(Response.json(results), ACCEPTED);
}RFC 10008 puts real obligations on the server: it MUST reject a QUERY whose Content-Type is missing, it should tell clients which query formats it accepts (via Accept-Query), and it needs to answer the method-override fallback that clients use when they're unsure the server speaks QUERY. This library packages those rules so your handler stays about your query logic.
npm install @danmat/query-serverWhether a request should be handled as a QUERY. Recognizes the QUERY method and, by default, POST + X-HTTP-Method-Override: QUERY (the fallback used by clients like @danmat/query-fetch). Disable with { allowMethodOverride: false }.
Throws a QueryRequestError (carrying the correct HTTP status and headers) when the request isn't a valid QUERY:
| Condition | Status | Extra |
|---|---|---|
| Not a QUERY request | 405 |
Allow: QUERY |
Missing Content-Type |
400 |
— |
Content-Type not in accept |
415 |
Accept-Query: … |
Pass { accept: ["application/json", …] } to enable media-type negotiation (wildcards and parameters supported).
Non-throwing companion — returns a ready-to-send error Response, or null when the request is valid.
Reads the body as JSON, guarding the content type (415 for a non-JSON type, 400 for malformed JSON).
Builds an Accept-Query header value from the media types you accept (strings and/or structured ranges with q weights).
Returns a copy of response with the Accept-Query header set — handy on both success and 415 responses.
Error subclass with status: number, headers: Record<string,string>, and toResponse(): Response.
@danmat/query-fetch— client for the QUERY method.@danmat/accept-query— parse/build/negotiateAccept-Query.@danmat/query-cache— body-aware response caching.@danmat/query-server— server-side request validation & negotiation (you are here).
MIT © Dan Matthew