Skip to content

feat: add requireContentType and appendAcceptQuery utils#1446

Merged
pi0 merged 7 commits into
mainfrom
feat/query-utils
Jul 9, 2026
Merged

feat: add requireContentType and appendAcceptQuery utils#1446
pi0 merged 7 commits into
mainfrom
feat/query-utils

Conversation

@pi0x

@pi0x pi0x commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Follow-up to QUERY method support (#1445), implementing the header/validation utilities from the RFC 10008 plan in #1441.

appendAcceptQuery(event, mediaTypes)

Advertises the query formats a resource accepts via the Accept-Query response header, serialized as an RFC 8941 Structured Fields List. Base media types become tokens; ;name=value parameters are emitted as quoted strings (validated tokens/keys, escaped quotes/backslashes, empty-list is a no-op).

appendAcceptQuery(event, ["application/sql;charset=UTF-8", "application/jsonpath"]);
// Accept-Query: application/sql;charset="UTF-8", application/jsonpath

requireContentType(event, acceptedTypes)

Opt-in Content-Type validation returning the matched media type. Throws per RFC:

  • 400 — missing Content-Type
  • 422 — malformed Content-Type
  • 415 — unsupported media type

Supports */*, *, and type/* wildcards.

app.query("/search", async (event) => {
  requireContentType(event, ["application/sql", "application/jsonpath"]);
  const body = await readBody(event, { type: "text" });
});

Notes

  • New module src/utils/query.ts; exports added to src/index.ts.
  • Docs generated into docs/2.utils/1.request.md (automd).
  • Tests in test/query.test.ts (web + node matrix); package-exports snapshot updated.
  • pnpm lint + pnpm vitest run green (1315 passed).

A getResponseAcceptQuery reader was considered but dropped — reading back a header the same handler just set has no real use; the serialization is the part that carries value.

Remaining from #1441: PR 4 (CORS preflight / cache-header / proxy body-forwarding audits).

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added support for QUERY-related helpers to validate request content types and advertise accepted query formats.
    • Added a demo example showing QUERY requests, cached results, and cacheable links for query responses.
  • Bug Fixes

    • Improved media type handling with wildcard support and parameter stripping on successful matches.
    • Added stricter validation for malformed, missing, and unsupported content types.
  • Tests

    • Expanded coverage for query header formatting, quoting behavior, wildcard matching, and error responses.

@pi0x
pi0x requested a review from pi0 as a code owner July 9, 2026 11:45
@coderabbitai

coderabbitai Bot commented Jul 9, 2026

Copy link
Copy Markdown

Review Change Stack

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: da805fdf-efe7-41d3-bd72-60d56386238a

📥 Commits

Reviewing files that changed from the base of the PR and between 39934ac and a8e11fa.

📒 Files selected for processing (5)
  • docs/2.utils/1.request.md
  • src/index.ts
  • src/utils/query.ts
  • test/query.test.ts
  • test/unit/package.test.ts

📝 Walkthrough

Walkthrough

Adds RFC 10008 HTTP QUERY helpers for Accept-Query serialization and Content-Type validation, exposes them from the package entrypoint, documents the API, updates export snapshots, and adds a dedicated example plus tests.

Changes

Query utilities implementation

Layer / File(s) Summary
Core query utility functions and structured-fields helpers
src/utils/query.ts
Adds appendAcceptQuery and requireContentType plus internal serialization, matching, parsing, and escaping helpers.
Exports wiring
src/index.ts
Re-exports appendAcceptQuery and requireContentType from the package entrypoint.
Tests and export snapshot updates
test/query.test.ts, test/unit/package.test.ts
Adds query utility tests and updates the package export snapshot to include the new symbols.
Documentation for QUERY utilities
docs/2.utils/1.request.md
Adds the Query documentation section for the new helpers and their RFC 10008 behavior.
QUERY example app
examples/query.mjs
Adds an H3 demo server for RFC 10008 QUERY handling, including routes, client UI, caching, and query matching.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Possibly related issues

Suggested reviewers: pi0

Poem

A rabbit hops through headers new,
Structured fields, quoted true,
QUERY method finds its way,
Content-Type checked, come what may 🥕
Thump-thump — tests all pass today!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 57.14% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title matches the main change set: new request-content validation and Accept-Query response utilities, despite naming the second utility incorrectly.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/query-utils

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai

coderabbitai Bot commented Jul 9, 2026

Copy link
Copy Markdown

Caution

Failed to replace (edit) comment. This is likely due to insufficient permissions or the comment being deleted.

Error details
Connect Timeout Error (attempted address: api.github.com:443, timeout: 10000ms)

Follow-up to QUERY method support (#1445) for RFC 10008.

- `setResponseAcceptQuery` / `getResponseAcceptQuery`: advertise and read the
  supported query media types via the `Accept-Query` response header, serialized
  as a Structured Fields (RFC 8941) List.
- `requireContentType`: opt-in request `Content-Type` validation throwing
  `400` (missing), `422` (malformed), or `415` (unsupported), with wildcard
  support (`*/*`, `type/*`).

Co-Authored-By: Claude Opus 4.8 <[email protected]>
@pi0x
pi0x force-pushed the feat/query-utils branch from a1bdcd5 to 2740b9c Compare July 9, 2026 11:49
Follow-up to QUERY method support (#1445) for RFC 10008.

- `setResponseAcceptQuery`: advertise the supported query media types via the
  `Accept-Query` response header, serialized as a Structured Fields (RFC 8941)
  List.
- `requireContentType`: opt-in request `Content-Type` validation throwing
  `400` (missing), `422` (malformed), or `415` (unsupported), with wildcard
  support (`*/*`, `type/*`).

Co-Authored-By: Claude Opus 4.8 <[email protected]>
@pi0x pi0x changed the title feat(query): Accept-Query header + Content-Type validation utils feat(query): add setResponseAcceptQuery and requireContentType utils Jul 9, 2026
Follow-up to QUERY method support (#1445) for RFC 10008.

- `setAcceptQuery`: advertise the supported query media types via the
  `Accept-Query` response header, serialized as a Structured Fields (RFC 8941)
  List.
- `requireContentType`: opt-in request `Content-Type` validation throwing
  `400` (missing), `422` (malformed), or `415` (unsupported), with wildcard
  support (`*/*`, `type/*`).

Co-Authored-By: Claude Opus 4.8 <[email protected]>
@pi0x pi0x changed the title feat(query): add setResponseAcceptQuery and requireContentType utils feat(query): add setAcceptQuery and requireContentType utils Jul 9, 2026
@pi0 pi0 changed the title feat(query): add setAcceptQuery and requireContentType utils feat: add requireContentType and setAcceptQuery utils Jul 9, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
test/query.test.ts (1)

102-120: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Consider adding a test for the bare * wildcard.

mediaTypeMatches handles accepted === "*" (line 121 in query.ts), but no test covers this case. The */* wildcard is tested, but the bare * variant is not.

🧪 Suggested test
     it("supports the */* wildcard", async () => {
       t.app.query("/any", (event) => requireContentType(event, "*/*"));
       const res = await t.fetch("/any", {
         method: "QUERY",
         body: "x",
         headers: { "content-type": "text/plain" },
       });
       expect(res.status).toBe(200);
     });
+
+    it("supports the bare * wildcard", async () => {
+      t.app.query("/star", (event) => requireContentType(event, "*"));
+      const res = await t.fetch("/star", {
+        method: "QUERY",
+        body: "x",
+        headers: { "content-type": "text/plain" },
+      });
+      expect(res.status).toBe(200);
+    });
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/query.test.ts` around lines 102 - 120, Add a test in query.test.ts
covering the bare "*" wildcard path, since mediaTypeMatches explicitly supports
accepted === "*" in query.ts but current coverage only checks "application/*"
and "*/*". Mirror the existing query tests by registering a handler with
requireContentType(event, "*") and asserting a QUERY request with a
representative content-type (for example text/plain) returns 200.
src/utils/query.ts (1)

91-93: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Consider using k prefix for constants per project convention.

SF_TOKEN_RE and SF_KEY_RE don't follow the k prefix convention used elsewhere in the codebase (e.g., kEventRes, kMalformedURL). As per coding guidelines, symbol constants should use the k prefix (e.g., kNotFound, kHandled).

♻️ Optional refactor
-const SF_TOKEN_RE = /^[A-Za-z*][\w!#$%&'*+.^`|~:/-]*$/;
-const SF_KEY_RE = /^[a-z*][a-z0-9_.*-]*$/;
+const kSfTokenRe = /^[A-Za-z*][\w!#$%&'*+.^`|~:/-]*$/;
+const kSfKeyRe = /^[a-z*][a-z0-9_.*-]*$/;

And update references in serializeMediaType accordingly.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/utils/query.ts` around lines 91 - 93, Rename the constant regex symbols
in query.ts to follow the project’s k-prefix convention by changing SF_TOKEN_RE
and SF_KEY_RE to kSF_TOKEN_RE and kSF_KEY_RE, then update all references in
serializeMediaType and any nearby usage to match the new names. Keep the
behavior unchanged and ensure the new identifiers remain consistent with other
constants like kEventRes and kMalformedURL.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@src/utils/query.ts`:
- Around line 91-93: Rename the constant regex symbols in query.ts to follow the
project’s k-prefix convention by changing SF_TOKEN_RE and SF_KEY_RE to
kSF_TOKEN_RE and kSF_KEY_RE, then update all references in serializeMediaType
and any nearby usage to match the new names. Keep the behavior unchanged and
ensure the new identifiers remain consistent with other constants like kEventRes
and kMalformedURL.

In `@test/query.test.ts`:
- Around line 102-120: Add a test in query.test.ts covering the bare "*"
wildcard path, since mediaTypeMatches explicitly supports accepted === "*" in
query.ts but current coverage only checks "application/*" and "*/*". Mirror the
existing query tests by registering a handler with requireContentType(event,
"*") and asserting a QUERY request with a representative content-type (for
example text/plain) returns 200.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: c35ccbe0-d06b-4b2f-90d4-c7081e8cdfd6

📥 Commits

Reviewing files that changed from the base of the PR and between a6ba340 and b7cfdcb.

📒 Files selected for processing (5)
  • docs/2.utils/1.request.md
  • src/index.ts
  • src/utils/query.ts
  • test/query.test.ts
  • test/unit/package.test.ts

pi0 and others added 2 commits July 9, 2026 12:12
- match accepted media types that carry parameters (strip params both sides)
- return 422 for structurally malformed Content-Type (empty type/subtype)
- accumulate Accept-Query across multiple setAcceptQuery calls instead of overwriting
- render requireContentType `Throws:` JSDoc as a proper bulleted list

Co-Authored-By: Claude Opus 4.8 <[email protected]>
@pi0x pi0x mentioned this pull request Jul 9, 2026
13 tasks
The function appends to an existing Accept-Query header rather than
overwriting it, so the name should reflect accumulation semantics.
@pi0x pi0x changed the title feat: add requireContentType and setAcceptQuery utils feat: add requireContentType and appendAcceptQuery utils Jul 9, 2026
@pi0
pi0 merged commit 71295c6 into main Jul 9, 2026
7 of 9 checks passed
@pi0
pi0 deleted the feat/query-utils branch July 9, 2026 14:25
@pi0x pi0x mentioned this pull request Jul 9, 2026
pi0x pushed a commit that referenced this pull request Jul 9, 2026
- examples/query.mjs imported `setAcceptQuery`, but the util shipped as
  `appendAcceptQuery` (#1446) — the example failed to run. Verified the
  fixed example end-to-end (QUERY, 415, cacheable GET follow-up).
- docs: add an "HTTP QUERY Method" example page walking through
  `app.query()`, `appendAcceptQuery`, `requireContentType`, and the
  cacheable-GET / `Content-Location` pattern; link it from the routing
  guide and the examples index.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants