New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

zod-openapi

Package Overview
Dependencies
Maintainers
1
Versions
83
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

zod-openapi

A library to create full OpenAPI documents from your Zod types

  • 0.5.1
  • Source
  • npm
  • Socket score

Version published
Weekly downloads
0
decreased by-100%
Maintainers
1
Weekly downloads
 
Created
Source

zod-openapi

A Typescript library to create full OpenAPI 3 documentation from Zod Types.

npm version npm downloads Powered by skuba

Install

Install via npm:

npm install zod zod-openapi

API

extendZodWithOpenApi

Mutates Zod with an .openapi() method and extra metadata. Make a side-effectful import at the top of your entry point(s).

import { z } from 'zod';
import { extendZodWithOpenApi } from 'zod-openapi';

extendZodWithOpenApi(z);

z.string().openapi({ description: 'hello world!', example: 'hello world' });

createDocument

Creates an OpenAPI documentation object

import { z } from 'zod';
import { createDocument, extendZodWithOpenApi } from 'zod-openapi';

extendZodWithOpenApi(z);

const jobId = z.string().openapi({
  description: 'Job ID',
  examples: ['12345'],
});

const title = z.string().openapi({
  description: 'Job title',
  examples: ['My job'],
});

const document = createDocument({
  openapi: '3.1.0',
  info: {
    title: 'My API',
    version: '1.0.0',
  },
  paths: {
    '/jobs/{jobId}': {
      put: {
        requestParams: { path: z.object({ jobId }) },
        requestBody: {
          content: {
            'application/json': { schema: z.object({ title }) },
          },
        },
        responses: {
          '200': {
            description: '200 OK',
            content: {
              'application/json': { schema: z.object({ jobId, title }) },
            },
          },
        },
      },
    },
  },
});

Generates the following object:

{
  "openapi": "3.1.0",
  "info": {
    "title": "My API",
    "version": "1.0.0"
  },
  "paths": {
    "/jobs/{jobId}": {
      "put": {
        "parameters": [
          {
            "in": "path",
            "name": "jobId",
            "schema": {
              "type": "string",
              "description": "Job ID",
              "examples": ["12345"]
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "title": {
                    "type": "string",
                    "description": "Job title",
                    "examples": ["My job"]
                  }
                },
                "required": ["title"]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "200 OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "jobId": {
                      "type": "string",
                      "description": "Job ID",
                      "examples": ["12345"]
                    },
                    "title": {
                      "type": "string",
                      "description": "Job title",
                      "examples": ["My job"]
                    }
                  },
                  "required": ["jobId", "title"]
                }
              }
            }
          }
        }
      }
    }
  }
}

createDocumentJson

In the background it calls createDocument but instead outputs it as a JSON string using JSON.stringify. It takes an optional options object as the second parameter which can customize how the JSON string is outputted.

const document = createDocumentJson(
  {
    openapi: '3.1.0',
    info: {
      title: 'My API',
      version: '1.0.0',
    },
  },
  { options: 2 },
);

createDocumentYaml

In the background it calls createDocument but instead outputs it as a YAML string using the yaml library. It takes an optional options object as the second parameter which can customize how the YAML string is outputted.

const document = createDocumentYaml(
  {
    openapi: '3.1.0',
    info: {
      title: 'My API',
      version: '1.0.0',
    },
  },
  { options: { uniqueKeys: false } },
);

Usage

Request Parameters

Query, Path, Header & Cookie parameters can be created using the requestParams key under the method key as follows:

createDocument({
  paths: {
    '/jobs/:a': {
      put: {
        requestParams: {
          path: z.object({ a: z.string() }),
          query: z.object({ b: z.string() }),
          cookie: z.object({ cookie: z.string() }),
          header: z.object({ 'custom-header': z.string() }),
        },
      },
    },
  },
});

If you would like to declare parameters using OpenAPI syntax you may also declare them using the parameters key. The definitions will then all be combined.

Request Body

Where you would normally declare the media type, instead declare the content as application/json and set the schema as your Zod Schema as follows.

createDocument({
  paths: {
    '/jobs': {
      get: {
        requestBody: {
          content: {
            'application/json': { schema: z.object({ a: z.string() }) },
          },
        },
      },
    },
  },
});

If you wish to use OpenAPI syntax for your schemas, simply add an OpenAPI schema to the schema field instead.

Responses

Similarly to the Request Body, simply set the schema as your Zod Schema as follows. You can set the response headers using the responseHeaders key.

createDocument({
  paths: {
    '/jobs': {
      get: {
        responses: {
          200: {
            description: '200 OK',
            content: {
              'application/json': { schema: z.object({ a: z.string() }) },
            },
            responseHeaders: z.object({
              'header-key': z.string(),
            }),
          },
        },
      },
    },
  },
});

Creating Components

OpenAPI allows you to define reusable components and this library allows you to replicate that in a simple way.

Schema

If we take the example in createDocument and instead create title as follows

const title = z.string().openapi({
  description: 'Job title',
  examples: ['My job'],
  ref: 'jobTitle', // <- new field
});

Wherever title is used in schemas across the document, it will instead be created as a reference.

{
  "title": { "$ref": "#/components/schemas/jobTitle" }
}

title will then be outputted as a schema within the components section of the documentation.

{
  "components": {
    "schemas": {
      "jobTitle": {
        "type": "string",
        "description": "Job title",
        "examples": ["My job"]
      }
    }
  }
}

This can be an extremely powerful way to generate better Open API documentation. There are some Open API features like discriminator mapping which require all schemas in the union to contain a ref.

To display components which are not referenced in the responses or requests simply add the Zod Schema to the schema components directly.

eg.

{
  "components": {
    "schemas": {
      MyJobSchema // note: this will register this Zod Schema as MyJobSchema unless `ref` in `openapi()` is specified on the type
    }
  }
}
Zod Effects

.transform() is complicated because it technically comprises of two types (input & output). This means that we need to understand which type you are creating. If you are adding the ZodSchema directly to the components section, context is required with knowing to create an input schema or an output schema. You can do this by setting the refType field to input or output in .openapi(). This defaults to output by default.

.preprocess() will always return the output type even if we are creating an input schema. If a different input type is required you can achieve this with a .transform() combined with a .pipe() or simply declare a manual type in .openapi().

If a registered schema with a ZodEffect is used in both a request and response schema you will receive an error because the created schema for each will be different. To override the creation type for a specific ZodEffect, add an .openapi() field to the ZodEffect and set the effectType field to input or output.

Parameters

Query, Path, Header & Cookie parameters can be similarly registered:

const jobId = z.string().openapi({
  description: 'Job ID',
  examples: ['1234'],
  param: { ref: 'jobId' },
});
Response Headers

Response headers can be similarly registered:

const header = z.string().openapi({
  description: 'Job ID',
  examples: ['1234'],
  header: { ref: 'some-header' },
});

Supported OpenAPI Versions

  • '3.0.0'
  • '3.0.1'
  • '3.0.2'
  • '3.0.3'
  • '3.1.0'

Supported Zod Schema

  • ZodArray
    • minItems/maxItems mapping for .length(), .min(), .max()
  • ZodBoolean
  • ZodCatch
  • ZodDate
    • string type mapping by default
  • ZodDefault
  • ZodDiscriminatedUnion
    • discriminator mapping when all schemas in the union contain a ref.
  • ZodEffects
    • transform support for request schemas. Wrap your transform in a ZodPipeline to enable response schema creation or declare a manual type in the .openapi() section of that schema.
    • pre-process full support.
    • refine full support.
  • ZodEnum
  • ZodLiteral
  • ZodNativeEnum
    • supporting string, number and combined enums.
  • ZodNull
  • ZodNullable
  • ZodNumber
    • integer type mapping for .int()
    • exclusiveMin/min/exclusiveMax/max mapping for .min(), .max(), lt(), gt()
  • ZodObject
  • ZodOptional
  • ZodPipeline
  • ZodRecord
  • ZodString
    • format mapping for .url(), .uuid(), .email(), .datetime()
    • minLength/maxLength mapping for .length(), .min(), .max()
    • pattern mapping for .regex()
  • ZodTuple
    • items mapping for .rest()
  • ZodUnion

If this library cannot determine a type for a Zod Schema, it will throw an error. To avoid this, declare a manual type in the .openapi() section of that schema.

eg.

z.custom().openapi({ type: 'string' });

Ecosystem

  • eslint-plugin-zod-openapi - Eslint rules for zod-openapi. This includes features which can autogenerate Typescript comments for your Zod types based on your description, example and deprecated fields.

Development

Prerequisites

  • Node.js LTS
  • Yarn 1.x
yarn install

Test

yarn test

Lint

# Fix issues
yarn format

# Check for issues
yarn lint

Release

To release a new version

  1. Create a new GitHub Release
  2. Select 🏷️ Choose a tag, enter a version number. eg. v1.2.0 and click + Create new tag: vX.X.X on publish.
  3. Click the Generate release notes button and adjust the description.
  4. Tick the Set as the latest release box and click Publish release. This will trigger the Release workflow.
  5. Check the Pull Requests tab for a PR labelled Release vX.X.X.
  6. Click Merge Pull Request on that Pull Request to update master with the new package version.

To release a new beta version

  1. Create a new GitHub Release
  2. Select 🏷️ Choose a tag, enter a version number with a -beta.X suffix eg. v1.2.0-beta.1 and click + Create new tag: vX.X.X-beta.X on publish.
  3. Click the Generate release notes button and adjust the description.
  4. Tick the Set as a pre-release box and click Publish release. This will trigger the Prerelease workflow.

Credits

  • @asteasolutions/zod-to-openapi - zod-openapi was created while trying to re-write the wonderful library to support auto registering schemas. However, the underlying structure of the library which consists of tightly coupled classes would not allow for this be done easily. As a result zod-openapi was born with the goal of keeping the Zod Schemas independent from the generation of the documentation.

FAQs

Package last updated on 18 Apr 2023

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc