next-openapi-gen

repository·main·Indexed 41 days ago

https://github.com/tazo90/next-openapi-gen

A tool that generates OpenAPI 3.0, 3.1, and 3.2 specifications by scanning route handlers and schemas. It supports Zod, TypeScript, and Drizzle-Zod schemas across multiple frameworks including Next.js (App and Pages Router), TanStack Router, React Router, Remix, SvelteKit, Nuxt, Astro, Hono, and Express. It uses JSDoc tags like @openapi, @body, and @response to link schemas to endpoints and provides a CLI for initialization and generation.

Tokens
53.2K
Snippets
164
Records
251
Agent score
51%

What's inside next-openapi-gen

  1. Understand cache hits and artifact side effects

    main

    A cache hit returns the prior result without rerunning the core generation process. However, if you have configured any artifact side effects, the generator will reuse the cached base OpenAPI document but will rerun the artifact pipeline.

    Artifact side effects are triggered when:

    • docs is configured and docs.enabled !== false
    • Any clientSdk entry has enabled !== false
    • arazzo is configured
    • overlay is configured
    • hooks.artifactsWritten is configured

    When a cache hit occurs, the following can run again: Overlay application, spec write, Arazzo, docs, client SDK commands, and artifactsWritten. The result will report cached: true.

    Note: Hooks used for building the base document (configLoaded, routesDiscovered, and documentBuilt) do not run during a cache hit.

  2. Use reusable actions in OpenAPI Overlay 1.2

    main

    In OpenAPI Overlay version 1.2, you can define reusable actions under components.actions. These actions are then referenced within the actions block using a same-document $ref and must include a required target.

    You can optionally specify a targetFormat to declare the kind of target document. Supported values include:

    • openapi
    • asyncapi
    • arazzo
    • An absolute URI

    Note: If the targetFormat disagrees with the generated OpenAPI document, the tool will emit an OVERLAY_TARGET_FORMAT_MISMATCH error and skip that specific apply file.

  3. Understand the generator performance report structure

    main

    The generator report (tests/bench/generator/current.json) provides detailed timing data for the generation process. Key fields include:

    • machine: CPU, OS, and Node metadata.
    • iterations: Number of samples averaged for each scenario.
    • scenarios: Cold and warm summaries keyed by fixture, framework, schema flavor, router, and OpenAPI version.
    • topPhases: The five slowest phase timers for quick triage.

    Triage Tip: Use the cold/warm ratio as a signal for cache effectiveness. If warm time is close to cold time, it indicates that route file parsing, schema discovery, or TypeScript inference is still rebuilding too much state unnecessarily.

  4. Use Built-in Authentication Presets

    main

    The generator provides three built-in authentication presets that automatically emit the necessary securitySchemes in your OpenAPI specification if they are referenced but not explicitly defined:

    1. bearer (maps to BearerAuth)
    2. basic (maps to BasicAuth)
    3. apikey (maps to ApiKeyAuth)

    If you use @auth bearer in a route, the generator will ensure BearerAuth is added to components.securitySchemes. You can remap these presets in your openapi-gen.config.ts using the authPresets key. For example, to rename the bearer preset to JwtAuth:

    authPresets: {
      bearer: "JwtAuth"
    }
    authPresets: {
      bearer: "JwtAuth"
    }
  5. Configure schema resolution strategies

    main

    You can define how next-openapi-gen discovers your API contracts using schemaType and schemaDir.

    • Zod-first: Use when contracts live in exported Zod schemas.
    • TypeScript-first: Use when contracts live in exported TypeScript types.
    • Mixed schemas: Use for migrations or combining code schemas with external fragments. Resolution priority is: schemaFiles > zod > typescript.
    // Zod-first
    {
      schemaType: "zod",
      schemaDir: "./src/schemas"
    }
    
    // TypeScript-first
    {
      schemaType: "typescript",
      schemaDir: "./src/types"
    }
    
    // Mixed schemas
    {
      schemaType: ["zod", "typescript"],
      schemaDir: "./src/schemas",
      schemaFiles: ["./schemas/external-api.yaml"]
    }
  6. Core rule for JSDoc documentation in next-openapi-gen

    main
    When documenting routes, use explicit JSDoc tags to ensure stable and predictable OpenAPI output. Specifically, providing explicit @response metadata will always take precedence over any responses that the generator attempts to infer automatically.
  7. Automatic schema inference from handlers

    main

    The generator can resolve Zod schemas without explicit JSDoc tags (like @pathParams or @body) if the handler calls the schema directly on the context.

    Supported patterns include:

    • schema.parse(await context.params)
    • Parsing query data from searchParams
    • Parsing JSON or form bodies

    Note: Explicit JSDoc tags still take priority over this automatic inference.

  8. Understand the coverage model

    main

    The project distinguishes between two types of features in its OpenAPI generation:

    1. Generated features: These are derived directly from route metadata (JSDoc), schemas (Zod/TypeScript), and type inference.
    2. Preserved features: These are maintained via openapi-gen.config.ts, schemaFiles, or custom OpenAPI fragments. These allow you to inject manual OpenAPI definitions that aren't strictly derived from the code's types.
  9. Leverage checker-assisted OpenAPI improvements

    main

    The generator uses a selective checker-assisted approach to improve schema accuracy without requiring a full-project type-check architecture. Key improvements include:

    • Response Inference: App Router response inference can reuse named schemas when the checker resolves the response type. Inline object returns emit a best-effort inline schema rather than being dropped.
    • Static Analysis: Multiple return paths and explicit 204 responses are collected when statically identifiable from Response.json(...) or NextResponse.json(...) returns.
    • TypeScript Resolution:
      • tsconfig.json path aliases are resolved for TypeScript schema discovery.
      • The checker handles complex types (mapped, conditional, template-literal, keyof, and import-based named types) that would otherwise collapse to broad objects during Babel-only analysis.
  10. Use built-in security presets

    main

    The generator provides three built-in security scheme presets. When you use these keywords in your @auth or @security tags, the generator will automatically emit the corresponding security scheme objects in the components.securitySchemes section of your OpenAPI specification if they are missing.

    Supported Presets

    • bearer: Generates an HTTP Bearer scheme (JWT format).
    • basic: Generates an HTTP Basic auth scheme.
    • apikey: Generates an apiKey scheme located in the header with the name X-Api-Key.

    Usage Notes

    • @auth: This is a shortcut tag that applies presets to scheme names after parsing.
    • @security: This is the standard way to document scopes. It also supports the same presets.
    • Custom Schemes: If you use a name that does not match a built-in preset (e.g., SessionCookie), the generator will not automatically create a scheme object for it; you must define it manually in your components.
    // Example of what the generator emits for built-in keywords
    {
      bearer: { type: "http", scheme: "bearer", bearerFormat: "JWT" },
      basic: { type: "http", scheme: "basic" },
      apikey: { type: "apiKey", in: "header", name: "X-Api-Key" }
    }
  11. Handle nullability and nullish values in Zod schemas

    main

    The generator handles .nullable() and .nullish() by adjusting the emitted schema based on the target OpenAPI version:

    • OpenAPI 3.0: Emits nullable: true.
    • OpenAPI 3.1+: Emits type: [..., "null"] for primitive types.
    • Named Schema References ($ref): Emits anyOf: [{ $ref }, { type: "null" }]. For OpenAPI 3.0, the version processor automatically downgrades this to { allOf: [{ $ref }], nullable: true } to maintain compatibility.
  12. Decouple OpenAPI component names from source identifiers

    main

    If you want the OpenAPI component name (e.g., in components.schemas) to differ from your TypeScript export name or Zod variable name, use the following methods:

    For Zod schemas

    Use .meta({ id: 'Name' }) to set the component ID.

    export const audioSchema = z.object({ ... }).meta({ id: "Audio" });
    // Result: components.schemas.Audio

    For TypeScript types

    Use the /** @id Name */ JSDoc tag at the declaration level.

    /** @id Audio */
    export interface AudioInterface { ... }
    // Result: components.schemas.Audio

    Existing @requestBody or @response references in your route handlers will resolve to these custom IDs automatically.

    /** @id Audio */
    export interface AudioInterface { ... }