Skip to content

Conversation

@mwillbanks
Copy link

@mwillbanks mwillbanks commented Nov 17, 2025

Summary

  • add a dedicated custom handler guide detailing the new ApiHandler contract, REST/RPC subclass hooks, and integration patterns
  • extend the REST and RPC handler references with concrete override examples, type references, and backlinks to the customization guide
  • provide a custom server adapter walkthrough featuring the shared adapter utilities and a minimal Node HTTP implementation

Additional Context

  • cross-link the new materials throughout the handler and adapter docs so readers can discover customization workflows from multiple entry points
  • align terminology with the latest server package exports and highlight the shared logging/serialization helpers introduced upstream

Related Work

  • builds on the handler and adapter extension capabilities shipped in zenstack-v3#413

Summary by CodeRabbit

  • Documentation
    • Added a comprehensive guide for building custom server adapters, covering contracts, implementation outline, examples, and wiring guidance.
    • Added detailed guidance for creating and customizing API handlers, including REST and RPC extension patterns, examples, utilities, and a minimal handler example.
    • Updated the server-adapter catalog to include the custom adapter option.
    • Minor doc cleanups and placement of new "Customizing the handler" sections.

Copilot AI review requested due to automatic review settings November 17, 2025 21:31
@vercel
Copy link

vercel bot commented Nov 17, 2025

@mwillbanks is attempting to deploy a commit to the ZenStack Team on Vercel.

A member of the Team first needs to authorize it.

Copilot finished reviewing on behalf of mwillbanks November 17, 2025 21:32
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 17, 2025

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

Walkthrough

Adds new documentation for building custom server adapters and custom API handlers, extends REST and RPC handler docs with customization examples, and updates the server-adapter catalog to include a Custom adapter entry.

Changes

Cohort / File(s) Summary
Custom Server Adapter docs
versioned_docs/version-3.x/reference/server-adapters/custom.mdx
New doc describing when to build a Custom Server Adapter, core contracts (ApiHandler, RequestContext, Response, CommonAdapterOptions, logInternalError), implementation outline, minimal Node HTTP adapter example, request mapping, client resolution, and error handling.
Custom API Handler docs
versioned_docs/version-3.x/service/api-handler/custom.md
New doc explaining how to customize/implement ZenStack API handlers, covering extending RestApiHandler and RPCApiHandler, building handlers from scratch, extension points, utilities (registerCustomSerializers, getZodErrorMessage, log), and wiring examples.
Handler doc updates
versioned_docs/version-3.x/service/api-handler/rest.md, versioned_docs/version-3.x/service/api-handler/rpc.md
Added "Customizing the handler" sections: RestApiHandler extension example (PublishedOnlyRestHandler) and RPCApiHandler Base64QueryHandler example plus exported handler instance; small formatting tweaks.
Server adapter catalog update
versioned_docs/version-3.x/service/server-adapter.md
Added "Custom" entry to the server-adapter catalog list.

Sequence Diagram(s)

sequenceDiagram
    autonumber
    participant Client as Client (HTTP)
    participant Adapter as Custom Server Adapter
    participant Handler as ApiHandler (Rest/RPC)
    participant DB as ZenStack Client / DB

    Client->>Adapter: Incoming request (method, path, headers, body)
    Adapter->>Handler: map request -> ApiHandler.processRequest / requestContext
    alt success
        Handler->>DB: resolve client / execute query
        DB-->>Handler: query result
        Handler-->>Adapter: Response {status, headers, body}
    else error
        Handler-->>Adapter: error payload / logInternalError
    end
    Adapter-->>Client: send HTTP response
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Verify TypeScript examples compile and match public API names (RestApiHandler, RPCApiHandler).
  • Confirm exported handler in RPC doc matches example usage and naming.
  • Check consistency between adapter contract names (RequestContext, CommonAdapterOptions, logInternalError) and library surface.

Possibly related PRs

Suggested reviewers

  • ymc9

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main changes: adding documentation for custom API handlers and server adapters in the v3 documentation.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8f047a7 and a873b9a.

📒 Files selected for processing (5)
  • versioned_docs/version-3.x/reference/server-adapters/custom.mdx (1 hunks)
  • versioned_docs/version-3.x/service/api-handler/custom.md (1 hunks)
  • versioned_docs/version-3.x/service/api-handler/rest.md (1 hunks)
  • versioned_docs/version-3.x/service/api-handler/rpc.md (1 hunks)
  • versioned_docs/version-3.x/service/server-adapter.md (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • versioned_docs/version-3.x/service/api-handler/rpc.md
  • versioned_docs/version-3.x/reference/server-adapters/custom.mdx
  • versioned_docs/version-3.x/service/api-handler/custom.md
🔇 Additional comments (2)
versioned_docs/version-3.x/service/server-adapter.md (1)

50-50: Simple and clear catalog update.

The new Custom adapter entry follows the established format and complements the new reference documentation mentioned in the PR objectives.

versioned_docs/version-3.x/service/api-handler/rest.md (1)

969-1008: All verifications passed—no issues found.

The cross-reference to ./custom correctly resolves to the custom.md file in the same directory, and the content aligns perfectly with the extension patterns discussed in rest.md. The generic type syntax RestApiHandler<typeof schema> matches the documented API shown in custom.md (using RestApiHandler<Schema>), and all protected methods mentioned—buildFilter, handleGenericError, processRequestBody, buildRelationSelect—are properly documented in the custom handler guide.


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 and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (3)
versioned_docs/version-3.x/service/api-handler/custom.md (3)

12-12: Hyphenate compound adjective "brand-new".

The phrase "author brand new handlers" should use a hyphenated form since it's a compound adjective modifying "handlers".

- override parts of the REST or RPC pipeline (filtering, serialization, validation, error handling, and more);
- wrap the default handlers with extra behavior (multi-tenancy, telemetry, custom logging);
- implement a handler from scratch while still benefiting from ZenStack's schema and serialization helpers.

Apply this correction:

- override parts of the REST or RPC pipeline (filtering, serialization, validation, error handling, and more);
- wrap the default handlers with extra behavior (multi-tenancy, telemetry, custom logging);
- implement a brand-new handler from scratch while still benefiting from ZenStack's schema and serialization helpers.

82-82: Simplify "Refer back to" → "See".

The phrase "Refer back to" is unnecessarily wordy. Use a more concise alternative.

- Refer back to the [RESTful API Handler](./rest) page for the canonical behavior and extension points.
+ See the [RESTful API Handler](./rest) page for canonical behavior and extension points.

119-119: Simplify "Refer back to" → "See".

The phrase "Refer back to" is unnecessarily wordy. Use a more concise alternative.

- Refer back to the [RPC API Handler](./rpc) page for the canonical behavior and endpoint matrix.
+ See the [RPC API Handler](./rpc) page for canonical behavior and endpoint matrix.
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 66ea0da and fe59ca9.

📒 Files selected for processing (5)
  • versioned_docs/version-3.x/reference/server-adapters/custom.mdx (1 hunks)
  • versioned_docs/version-3.x/service/api-handler/custom.md (1 hunks)
  • versioned_docs/version-3.x/service/api-handler/rest.md (1 hunks)
  • versioned_docs/version-3.x/service/api-handler/rpc.md (1 hunks)
  • versioned_docs/version-3.x/service/server-adapter.md (1 hunks)
🧰 Additional context used
🪛 LanguageTool
versioned_docs/version-3.x/service/api-handler/custom.md

[grammar] ~12-~12: Use a hyphen to join words.
Context: ...an tailor their behavior or author brand new handlers without leaving TypeScript....

(QB_NEW_EN_HYPHEN)


[style] ~82-~82: ‘Refer back’ might be wordy. Consider a shorter alternative.
Context: ...Ids` to expose bespoke query features. Refer back to the RESTful API Handler pa...

(EN_WORDINESS_PREMIUM_REFER_BACK)


[style] ~119-~119: ‘Refer back’ might be wordy. Consider a shorter alternative.
Context: ...subset of models to a specific client. Refer back to the RPC API Handler page fo...

(EN_WORDINESS_PREMIUM_REFER_BACK)

🔇 Additional comments (9)
versioned_docs/version-3.x/service/api-handler/rest.md (1)

967-1008: Well-structured customization guide with clear example.

The new section effectively demonstrates handler extension through a practical example. The forward reference to the comprehensive Custom API Handler guide at line 1008 provides good progression for readers wanting deeper guidance.

versioned_docs/version-3.x/service/api-handler/custom.md (3)

35-75: REST handler extension example is clear and practical.

The PublishedOnlyRestHandler demonstrates the intended pattern well: override a single protected method and delegate the rest to the base class. The example correctly shows how to merge custom filters with query-parsed filters.


85-120: RPC handler extension example demonstrates unmarshaling customization effectively.

The Base64QueryHandler shows how to intercept and transform query encoding before delegating to superjson deserialization. The note about Node's Buffer dependency and fallback suggestion for edge runtimes is pragmatic.


122-155: Handler-from-scratch implementation is instructive and minimal.

The HealthcheckHandler example effectively demonstrates the ApiHandler contract and the importance of calling registerCustomSerializers() once. The minimal implementation is approachable while still being complete.

versioned_docs/version-3.x/reference/server-adapters/custom.mdx (3)

9-11: Effective motivation for when to build a custom adapter.

The "When to build one" section clearly articulates the scenario and emphasizes code reuse through shared utilities, which is a good incentive.


30-98: Minimal Node HTTP adapter is a complete, instructive example.

The createNodeAdapter factory function demonstrates all essential pieces: URL parsing, client resolution with error handling, RequestContext construction, handler delegation, and response serialization. The error paths use logInternalError consistently with built-in adapters. The readJson helper correctly handles both string and Buffer chunks from the request stream.


100-111: Correct and defensive async iteration over request stream.

The readJson helper properly handles the async iterable protocol, buffers chunks, and safely parses empty payloads. The distinction between typeof chunk === 'string' and Buffer is correct for handling different Node versions.

versioned_docs/version-3.x/service/server-adapter.md (1)

50-50: Custom adapter catalog entry is correctly placed and formatted.

The addition to the catalog follows the established pattern and the link path is consistent with the file structure introduced in the PR.

versioned_docs/version-3.x/service/api-handler/rpc.md (1)

237-265: RPC handler customization section is clear and mirrors REST handler pattern well.

The section effectively demonstrates query decoding customization and properly documents the Node Buffer dependency with a fallback suggestion for edge runtimes. The tip at the end provides good continuity with the comprehensive Custom API Handler guide.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR adds comprehensive documentation for customizing API handlers and server adapters in ZenStack v3. The documentation covers extension patterns for the built-in REST and RPC handlers, as well as guidance for implementing custom handlers and server adapters from scratch.

Key Changes:

  • Added dedicated custom handler guide with ApiHandler contract details and extension patterns
  • Extended REST and RPC handler documentation with concrete override examples
  • Added custom server adapter walkthrough with minimal Node HTTP implementation

Reviewed Changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 9 comments.

Show a summary per file
File Description
versioned_docs/version-3.x/service/server-adapter.md Added navigation link to custom server adapter documentation
versioned_docs/version-3.x/service/api-handler/rpc.md Added customization section with unmarshalQ override example and cross-reference
versioned_docs/version-3.x/service/api-handler/rest.md Added customization section with buildFilter override example and cross-reference; removed blank line
versioned_docs/version-3.x/service/api-handler/custom.md New comprehensive guide covering handler extension patterns and custom implementation
versioned_docs/version-3.x/reference/server-adapters/custom.mdx New guide for building custom server adapters with Node HTTP example

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (4)
versioned_docs/version-3.x/service/api-handler/custom.md (4)

12-16: Address grammar and punctuation issues flagged in prior review.

Line 12 is a run-on sentence and uses "brand new" which should be "brand-new" (hyphenation for compound adjective). Lines 14–16 have inconsistent punctuation: the first two items end with semicolons, the last ends with a period. Apply one of the following fixes:

  • Option 1: Remove all punctuation (preferred for short items):
- override parts of the REST or RPC pipeline (filtering, serialization, validation, error handling, and more);
- wrap the default handlers with extra behavior (multi-tenancy, telemetry, custom logging);
- implement a handler from scratch while still benefiting from ZenStack's schema and serialization helpers.
+ override parts of the REST or RPC pipeline (filtering, serialization, validation, error handling, and more)
+ wrap the default handlers with extra behavior (multi-tenancy, telemetry, custom logging)
+ implement a handler from scratch while still benefiting from ZenStack's schema and serialization helpers
  • Option 2: Rewrite line 12 to break the run-on and fix hyphenation:
- ZenStack ships ready-to-use REST and RPC handlers, but you can tailor their behavior or author brand new handlers without leaving TypeScript. The server package exposes the handler contracts through `@zenstackhq/server/types` and utility helpers from `@zenstackhq/server/api`. All built-in handlers expose their methods as `protected` to allow for extension points. You can:
+ ZenStack ships ready-to-use REST and RPC handlers, but you can tailor their behavior or author brand-new handlers without leaving TypeScript. All built-in handlers expose their methods as `protected` to allow for extension points. You can:

39-48: Clarify generic type parameter for RestApiHandlerOptions.

The import at line 40 shows type RestApiHandlerOptions but the constructor parameter (line 46) is generic. Add a brief comment in the import block or just above the constructor to clarify that RestApiHandlerOptions must be parameterized with the schema type:

 import { RestApiHandler, type RestApiHandlerOptions } from '@zenstackhq/server/api';
 import { schema } from '~/zenstack/schema';

 type Schema = typeof schema;

 class PublishedOnlyRestHandler extends RestApiHandler<Schema> {
     constructor(options: RestApiHandlerOptions<Schema>) {
+        // RestApiHandlerOptions is generic and must be parameterized with your schema type
         super(options);
     }

56-59: Add inline comment explaining the type guard logic.

The defensive check at lines 57–59 ensures the filter is a plain object before spreading. Add a brief comment to clarify the intent:

         const existing =
             base.filter && typeof base.filter === 'object' && !Array.isArray(base.filter)
-                ? { ...(base.filter as Record<string, unknown>) }
+                ? { ...(base.filter as Record<string, unknown>) }  // ensure filter is a plain object before spreading
                 : {};

114-120: Use consistent terminology for examples and simplify "Refer back" phrasing.

Line 116 uses "for example" in parentheses, which is inconsistent with standardization on "e.g." elsewhere in the documentation. Additionally, line 119 uses "Refer back to" which may be wordy. Apply this fix:

- `processRequestPayload` for enforcing per-request invariants (for example, injecting tenant IDs);
+ `processRequestPayload` for enforcing per-request invariants (e.g., injecting tenant IDs);

And for line 119–120:

- Refer back to the [RPC API Handler](./rpc) page for the canonical behavior and endpoint matrix.
+ For canonical behavior and endpoint matrix, see [RPC API Handler](./rpc).
🧹 Nitpick comments (1)
versioned_docs/version-3.x/service/api-handler/custom.md (1)

77-83: Simplify "Refer back" phrasing.

Line 82 uses "Refer back to" which may be considered wordy. Consider a shorter alternative like "See" or "For details, see":

- Refer back to the [RESTful API Handler](./rest) page for the canonical behavior and extension points.
+ For canonical behavior and extension points, see [RESTful API Handler](./rest).
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between fe59ca9 and 8f047a7.

📒 Files selected for processing (2)
  • versioned_docs/version-3.x/reference/server-adapters/custom.mdx (1 hunks)
  • versioned_docs/version-3.x/service/api-handler/custom.md (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • versioned_docs/version-3.x/reference/server-adapters/custom.mdx
🧰 Additional context used
🪛 LanguageTool
versioned_docs/version-3.x/service/api-handler/custom.md

[grammar] ~12-~12: Use a hyphen to join words.
Context: ...an tailor their behavior or author brand new handlers without leaving TypeScript....

(QB_NEW_EN_HYPHEN)


[style] ~82-~82: ‘Refer back’ might be wordy. Consider a shorter alternative.
Context: ...Ids` to expose bespoke query features. Refer back to the RESTful API Handler pa...

(EN_WORDINESS_PREMIUM_REFER_BACK)


[style] ~119-~119: ‘Refer back’ might be wordy. Consider a shorter alternative.
Context: ...subset of models to a specific client. Refer back to the RPC API Handler page fo...

(EN_WORDINESS_PREMIUM_REFER_BACK)

🔇 Additional comments (3)
versioned_docs/version-3.x/service/api-handler/custom.md (3)

18-33: Core building blocks section is well‑structured.

The imports and accompanying descriptions clearly explain the role of each utility. This section sets up the foundation well for the handler extension examples.


122-155: "Implementing a handler from scratch" section is clear and correct.

The minimal HealthcheckHandler example effectively demonstrates the ApiHandler contract, including the schema property, log getter, and async handleRequest method. The emphasis on registerCustomSerializers() is appropriate and prevents a common integration pitfall.


157-173: Integration example is practical and well-linked.

The Express middleware example clearly demonstrates how custom handlers integrate with server adapters via the shared apiHandler option. The cross-link to custom server adapter documentation supports the PR's goal of surfacing customization workflows from multiple entry points.

- add custom API handler guide with extension examples
- update REST and RPC handler docs with customization guidance
- add custom server adapter reference and link from catalog
- refresh sidebar entries for the new content
@mwillbanks mwillbanks force-pushed the feat/server-handler-adapter-custom branch from 8f047a7 to a873b9a Compare November 17, 2025 22:34
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.

1 participant