Skip to content

DanMat/query-server

Repository files navigation

@danmat/query-server

CI npm version minified + gzip size License: MIT

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);
}

Why?

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.

Install

npm install @danmat/query-server

API

isQueryRequest(request, options?): boolean

Whether 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 }.

assertQueryRequest(request, options?): void

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).

checkQueryRequest(request, options?): Response | null

Non-throwing companion — returns a ready-to-send error Response, or null when the request is valid.

readQueryJson<T>(request): Promise<T>

Reads the body as JSON, guarding the content type (415 for a non-JSON type, 400 for malformed JSON).

acceptQueryHeader(mediaTypes): string

Builds an Accept-Query header value from the media types you accept (strings and/or structured ranges with q weights).

withAcceptQuery(response, mediaTypes): Response

Returns a copy of response with the Accept-Query header set — handy on both success and 415 responses.

QueryRequestError

Error subclass with status: number, headers: Record<string,string>, and toResponse(): Response.

The @danmat QUERY suite

▶️ See them work together: query-suite-example — a runnable demo using all four, with a 🌐 live playground.

License

MIT © Dan Matthew

About

Framework-agnostic server helpers for the HTTP QUERY method (RFC 10008): validate requests, negotiate content types, and advertise Accept-Query.

Topics

Resources

License

Code of conduct

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Packages

 
 
 

Contributors