A demo of the HTTP QUERY method
(RFC 10008)
in Django 6.2,
searching the 78,000 texts in the
Project Gutenberg catalog.
A search with many or structured criteria doesn't fit well in a URL: request lines have size
limits along the whole path (Gunicorn's default is 4094 bytes), and URLs end up in logs and
bookmarks. Sending the criteria as a POST body works, but tells every client, cache
and proxy that the request changes something. QUERY carries a body like
POST while being safe and idempotent like GET.
Edit the criteria and send them as a QUERY request to /books/,
straight from your browser:
The response will appear here.
Look up books by ID, a list that quickly outgrows a URL:
curl -X QUERY https://books.x14.nl/books/ \
-H 'Content-Type: application/json' \
-d '{"ids": [11, 84, 1342, 2701]}'
Combine structured filters:
curl -X QUERY https://books.x14.nl/books/ \
-H 'Content-Type: application/json' \
-d '{"language": ["nl", "fy"], "subject": ["Fiction"], "issued_before": "2005-01-01"}'
The same search as a GET, for comparison:
curl 'https://books.x14.nl/books/?language=nl&language=fy&subject=Fiction&issued_before=2005-01-01'
With a few thousand IDs that URL gets too long and the server answers
400 Bad Request; as a QUERY body they're no problem. Sending the
criteria as a POST instead fails with 403 Forbidden: without a CSRF
token, Django won't accept an unsafe request, while QUERY needs none.
Responses carry an ETag; repeat a query with -H 'If-None-Match: "…"' to
get 304 Not Modified. curl -i -X OPTIONS lists QUERY in
Allow, and every response advertises the accepted query format in
Accept-Query.
ids: list of Gutenberg ebook numbers (up to 10,000)title, author: text contained in the title or authorlanguage: one or more language codes; matches anysubject: one or more subject terms; matches allissued_after, issued_before: dates as YYYY-MM-DDlimit: number of results, 1 to 1000 (default 100)