npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

express-zod-openapi-autogen

v4.0.0

Published

This repository provides (relatively) un-opinionated utility methods for creating Express APIs that leverage Zod for request and response validation and auto-generate OpenAPI documentation.

Downloads

1,919

Readme

express-zod-openapi-autogen

This repository provides (relatively) un-opinionated utility methods for creating Express APIs that leverage Zod for request and response validation and auto-generate OpenAPI documentation.

Requirements

  • Express@^5.0
  • Zod@^3.14

Basic Use

In your route files, wrap each route handler in openAPIRoute. The tag, summary, and description determine how the route is grouped and presented in the OpenAPI schema.

  • The params, query, body and response are Zod schemas.

  • The openAPIRoute middleware will automatically validate that the incoming data matches your schemas and return 400 errors if required fields are missing, etc. Your route handler will receive typed fields (req.query will match your Zod schema) and you can trust that the data matches the schema.

  • The response schema is not required, but OpenAPI routes missing a response schema are documented as returning 204 No Content. If you provide a response schema, the Express res.json is typed to expect the schema. When NODE_ENV=development, the openAPIRoute middleware will console.warn if your response data does not align with your response schema.

  • If you omit one of the Zod schemas, no validation is performed and you receive the untyped data in your route handler.

router.get(
  '/users/:id',
  openAPIRoute(
    {
      tag: 'Users',
      summary: 'This is how you receive a specific user',
      description: 'Longer form details about the route',
      params: z.object({ id: z.string() }),
      query: z.object({ debugInfo: z.boolean().optional() }),
      response: UserSchema,
    },
    async (req, res) => {
      ...
    }
  )
);

Create a folder to hold your Zod schemas (eg: src/schemas), and export common types you plan to use repeatedly. For example, in our project we have UserSchema. Some APIs return UserSchema and others return z.array(UserSchema).

We'll pass a reference to these schemas to the OpenAPI generator, allowing it to define them as OpenAPI component schemas and reference them in our API route definitions.

In your Express application's app.ts file, load your route files containing public routes into an array, and pass them to buildOpenAPIDocument to create an OpenAPI schema. Note that buildOpenAPIDocument will throw errors if your Zod schemas are incomplete or cannot be translated to OpenAPI schemas.

import { buildOpenAPIDocument } from "express-zod-openapi-autogen";
import swaggerUI from "swagger-ui-express";

const PublicAPIs = [require("./routes/users").default, require("./routes/session").default];

// Attach API routes
for (const router of PublicAPIs) {
  app.use(`${prefix}/api`, router);
}

// Public documentation (auto-generated for all routes above this line)
try {
  const doc = buildOpenAPIDocument({
    routers: publicAPIs,
    schemaPaths: ["src/schemas"],
    config: {
      servers: [{ url: `https://server.com/api` }],
      info: {
        version: "1.0.0",
        title: "My API",
        description: `Welcome to the My API!`,
      },
    },
    errors: {
      401: "Unauthorized",
      403: "Forbidden",
    },
    openApiVersion: "3.0.0",
  });
  app.get(`/openapi.json`, (req, res) => res.json(doc));
  app.use(`/openapi`, swaggerUI.serve, swaggerUI.setup(doc));
} catch (err) {
  console.error(err);
}

Implementation Notes

  • Unless you use middleware that converts query parameters to other data types, you may find that ?option=false and ?option=100 are string values when your Zod schemas are validated. You can fix this by adding middleware that coerces these values to numbers/booleans, or by using Zod coerce:
export const OptionalQueryNumber = z.coerce.number().optional().openapi({ type: "number" });
  • If you'd like to provide example values, custom types, or descriptions for your Zod schemas, you can do so by chaining calls to z.openapi (shown in the example above). Note that .openapi({example: ...}) can be used on both individual fields and also on entire objects.

  • If you use z.any(), you may need to chain a call to z.openapi to specify what type should appear in the OpenAPI specification, since 'any' is not a valid OpenAPI type.