zod-openapi
Advanced tools
Comparing version 2.0.0 to 2.1.0
@@ -24,3 +24,3 @@ "use strict"; | ||
createRequestBodies(componentsObject.requestBodies, defaultComponents); | ||
createHeaders(componentsObject.responseHeaders, defaultComponents); | ||
createHeaders(componentsObject.headers, defaultComponents); | ||
createResponses(componentsObject.responses, defaultComponents); | ||
@@ -85,2 +85,5 @@ return defaultComponents; | ||
} | ||
if (!(responseHeaders instanceof zod_1.ZodType)) { | ||
return; | ||
} | ||
Object.entries(responseHeaders._def.shape()).forEach(([key, schema]) => { | ||
@@ -208,9 +211,12 @@ if (components.parameters.has(schema)) { | ||
const createHeaderComponents = (componentsObject, componentMap) => { | ||
const customComponents = Object.entries(componentsObject.headers ?? {}).reduce((acc, [key, value]) => { | ||
if (acc[key]) { | ||
throw new Error(`Header "${key}" is already registered`); | ||
} | ||
acc[key] = value; | ||
return acc; | ||
}, {}); | ||
const headers = componentsObject.headers ?? {}; | ||
const customComponents = headers instanceof zod_1.ZodType | ||
? {} | ||
: Object.entries(headers).reduce((acc, [key, value]) => { | ||
if (acc[key]) { | ||
throw new Error(`Header "${key}" is already registered`); | ||
} | ||
acc[key] = value; | ||
return acc; | ||
}, {}); | ||
const components = Array.from(componentMap).reduce((acc, [_zodType, component]) => { | ||
@@ -217,0 +223,0 @@ if (component.type === 'complete') { |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.createResponses = exports.createResponse = exports.createComponentHeaderRef = exports.createBaseHeader = exports.createHeaderOrRef = exports.createResponseHeaders = void 0; | ||
const zod_1 = require("zod"); | ||
const components_1 = require("./components"); | ||
@@ -12,6 +13,9 @@ const content_1 = require("./content"); | ||
} | ||
return Object.entries(responseHeaders.shape).reduce((acc, [key, zodSchema]) => { | ||
acc[key] = (0, exports.createHeaderOrRef)(zodSchema, components); | ||
return acc; | ||
}, {}); | ||
if (responseHeaders instanceof zod_1.ZodType) { | ||
return Object.entries(responseHeaders.shape).reduce((acc, [key, zodSchema]) => { | ||
acc[key] = (0, exports.createHeaderOrRef)(zodSchema, components); | ||
return acc; | ||
}, {}); | ||
} | ||
return responseHeaders; | ||
}; | ||
@@ -61,12 +65,2 @@ exports.createResponseHeaders = createResponseHeaders; | ||
exports.createComponentHeaderRef = createComponentHeaderRef; | ||
const createHeaders = (headers, responseHeaders, components) => { | ||
if (!responseHeaders && !headers) { | ||
return undefined; | ||
} | ||
const createdHeaders = (0, exports.createResponseHeaders)(responseHeaders, components); | ||
return { | ||
...headers, | ||
...createdHeaders, | ||
}; | ||
}; | ||
const createResponse = (responseObject, components) => { | ||
@@ -80,4 +74,4 @@ if ('$ref' in responseObject) { | ||
} | ||
const { content, headers, responseHeaders, ref, ...rest } = responseObject; | ||
const maybeHeaders = createHeaders(headers, responseHeaders, components); | ||
const { content, headers, ref, ...rest } = responseObject; | ||
const maybeHeaders = (0, exports.createResponseHeaders)(headers, components); | ||
const response = { | ||
@@ -84,0 +78,0 @@ ...rest, |
@@ -21,3 +21,3 @@ import { ZodType } from 'zod'; | ||
createRequestBodies(componentsObject.requestBodies, defaultComponents); | ||
createHeaders(componentsObject.responseHeaders, defaultComponents); | ||
createHeaders(componentsObject.headers, defaultComponents); | ||
createResponses(componentsObject.responses, defaultComponents); | ||
@@ -81,2 +81,5 @@ return defaultComponents; | ||
} | ||
if (!(responseHeaders instanceof ZodType)) { | ||
return; | ||
} | ||
Object.entries(responseHeaders._def.shape()).forEach(([key, schema]) => { | ||
@@ -200,9 +203,12 @@ if (components.parameters.has(schema)) { | ||
const createHeaderComponents = (componentsObject, componentMap) => { | ||
const customComponents = Object.entries(componentsObject.headers ?? {}).reduce((acc, [key, value]) => { | ||
if (acc[key]) { | ||
throw new Error(`Header "${key}" is already registered`); | ||
} | ||
acc[key] = value; | ||
return acc; | ||
}, {}); | ||
const headers = componentsObject.headers ?? {}; | ||
const customComponents = headers instanceof ZodType | ||
? {} | ||
: Object.entries(headers).reduce((acc, [key, value]) => { | ||
if (acc[key]) { | ||
throw new Error(`Header "${key}" is already registered`); | ||
} | ||
acc[key] = value; | ||
return acc; | ||
}, {}); | ||
const components = Array.from(componentMap).reduce((acc, [_zodType, component]) => { | ||
@@ -209,0 +215,0 @@ if (component.type === 'complete') { |
@@ -0,1 +1,2 @@ | ||
import { ZodType } from 'zod'; | ||
import { createComponentResponseRef } from './components'; | ||
@@ -9,6 +10,9 @@ import { createContent } from './content'; | ||
} | ||
return Object.entries(responseHeaders.shape).reduce((acc, [key, zodSchema]) => { | ||
acc[key] = createHeaderOrRef(zodSchema, components); | ||
return acc; | ||
}, {}); | ||
if (responseHeaders instanceof ZodType) { | ||
return Object.entries(responseHeaders.shape).reduce((acc, [key, zodSchema]) => { | ||
acc[key] = createHeaderOrRef(zodSchema, components); | ||
return acc; | ||
}, {}); | ||
} | ||
return responseHeaders; | ||
}; | ||
@@ -54,12 +58,2 @@ export const createHeaderOrRef = (schema, components) => { | ||
export const createComponentHeaderRef = (ref) => `#/components/headers/${ref}`; | ||
const createHeaders = (headers, responseHeaders, components) => { | ||
if (!responseHeaders && !headers) { | ||
return undefined; | ||
} | ||
const createdHeaders = createResponseHeaders(responseHeaders, components); | ||
return { | ||
...headers, | ||
...createdHeaders, | ||
}; | ||
}; | ||
export const createResponse = (responseObject, components) => { | ||
@@ -73,4 +67,4 @@ if ('$ref' in responseObject) { | ||
} | ||
const { content, headers, responseHeaders, ref, ...rest } = responseObject; | ||
const maybeHeaders = createHeaders(headers, responseHeaders, components); | ||
const { content, headers, ref, ...rest } = responseObject; | ||
const maybeHeaders = createResponseHeaders(headers, components); | ||
const response = { | ||
@@ -77,0 +71,0 @@ ...rest, |
@@ -16,5 +16,5 @@ import { AnyZodObject, ZodType } from 'zod'; | ||
} | ||
export interface ZodOpenApiResponseObject extends Omit<oas31.ResponseObject & oas30.ResponseObject, 'content'> { | ||
export interface ZodOpenApiResponseObject extends Omit<oas31.ResponseObject & oas30.ResponseObject, 'content' | 'headers'> { | ||
content?: ZodOpenApiContentObject; | ||
responseHeaders?: AnyZodObject; | ||
headers?: AnyZodObject | oas30.HeadersObject | oas31.HeadersObject; | ||
/** Use this field to auto register this response object as a component */ | ||
@@ -48,3 +48,3 @@ ref?: string; | ||
} | ||
export interface ZodOpenApiComponentsObject extends Omit<oas31.ComponentsObject & oas30.ComponentsObject, 'schemas' | 'responses' | 'requestBodies'> { | ||
export interface ZodOpenApiComponentsObject extends Omit<oas31.ComponentsObject & oas30.ComponentsObject, 'schemas' | 'responses' | 'requestBodies' | 'headers'> { | ||
schemas?: { | ||
@@ -57,3 +57,3 @@ [ref: string]: ZodType | oas31.SchemaObject | oas31.ReferenceObject | oas30.SchemaObject | oas30.ReferenceObject; | ||
requestParams?: ZodOpenApiParameters; | ||
responseHeaders?: AnyZodObject; | ||
headers?: AnyZodObject | oas31.HeadersObject | oas30.HeadersObject; | ||
responses?: { | ||
@@ -60,0 +60,0 @@ [ref: string]: ZodOpenApiResponseObject; |
import { AnyZodObject, ZodType } from 'zod'; | ||
import { oas31 } from '../openapi3-ts/dist'; | ||
import { oas30, oas31 } from '../openapi3-ts/dist'; | ||
import { ComponentsObject } from './components'; | ||
import { ZodOpenApiResponseObject, ZodOpenApiResponsesObject } from './document'; | ||
export declare const createResponseHeaders: (responseHeaders: AnyZodObject | undefined, components: ComponentsObject) => oas31.ResponseObject['headers']; | ||
export declare const createResponseHeaders: (responseHeaders: oas31.HeadersObject | oas30.HeadersObject | AnyZodObject | undefined, components: ComponentsObject) => oas31.ResponseObject['headers']; | ||
export declare const createHeaderOrRef: (schema: ZodType, components: ComponentsObject) => oas31.BaseParameterObject | oas31.ReferenceObject; | ||
@@ -7,0 +7,0 @@ export declare const createBaseHeader: (schema: ZodType, components: ComponentsObject) => oas31.BaseParameterObject; |
{ | ||
"name": "zod-openapi", | ||
"version": "2.0.0", | ||
"version": "2.1.0", | ||
"description": "A library to create full OpenAPI documents from your Zod types", | ||
@@ -39,3 +39,3 @@ "homepage": "https://github.com/samchungy/zod-openapi#readme", | ||
"@types/node": "^18.15.13", | ||
"eslint-plugin-zod-openapi": "^0.0.3", | ||
"eslint-plugin-zod-openapi": "^0.1.0", | ||
"openapi3-ts": "^4.1.2", | ||
@@ -42,0 +42,0 @@ "skuba": "6.0.2", |
128
README.md
@@ -1,16 +0,24 @@ | ||
# zod-openapi | ||
<p align="center"> | ||
<img src="zod-openapi.svg" width="200px" align="center" alt="zod-openapi logo" /> | ||
<h1 align="center">zod-openapi</h1> | ||
</p> | ||
<p align="center"> | ||
A Typescript library to create full OpenAPI 3.x documentation from <a href="https://github.com/colinhacks/zod">Zod</a> Schemas | ||
</p> | ||
<div align="center"> | ||
<a href="https://www.npmjs.com/package/zod-openapi"><img src="https://img.shields.io/npm/v/zod-openapi"/><a> | ||
<a href="https://www.npmjs.com/package/zod-openapi"><img src="https://img.shields.io/npm/dm/zod-openapi"/><a> | ||
<a href="https://nodejs.org/en/"><img src="https://img.shields.io/badge/node-%3E%3D%2016.11-brightgreen"/><a> | ||
<a href="https://github.com/seek-oss/skuba"><img src="https://img.shields.io/badge/🤿%20skuba-powered-009DC4"/><a> | ||
</div> | ||
<br> | ||
A Typescript library to create full OpenAPI 3.x documentation from [Zod](https://github.com/colinhacks/zod) Types. | ||
[](https://www.npmjs.com/package/zod-openapi) | ||
[](https://www.npmjs.com/package/zod-openapi) | ||
[](https://nodejs.org/en/) | ||
[](https://github.com/seek-oss/skuba) | ||
## Install | ||
Install via npm: | ||
Install via `npm` or `yarn`: | ||
```bash | ||
npm install zod zod-openapi | ||
## or | ||
yarn add zod zod-openapi | ||
``` | ||
@@ -202,3 +210,3 @@ | ||
Similarly to the [Request Body](#request-body), simply set the `schema` as your Zod Schema as follows. You can set the response headers using the `responseHeaders` key. | ||
Similarly to the [Request Body](#request-body), simply set the `schema` as your Zod Schema as follows. You can set the response headers using the `headers` key. | ||
@@ -216,3 +224,3 @@ ```typescript | ||
}, | ||
responseHeaders: z.object({ | ||
headers: z.object({ | ||
'header-key': z.string(), | ||
@@ -350,3 +358,3 @@ }), | ||
components: { | ||
responseHeaders: z.object( | ||
headers: z.object( | ||
'some-header': jobIdHeader | ||
@@ -486,49 +494,4 @@ ) | ||
## Development | ||
## Credits | ||
### Prerequisites | ||
- Node.js LTS | ||
- Yarn 1.x | ||
```shell | ||
yarn install | ||
``` | ||
### Test | ||
```shell | ||
yarn test | ||
``` | ||
### Lint | ||
```shell | ||
# Fix issues | ||
yarn format | ||
# Check for issues | ||
yarn lint | ||
``` | ||
### Release | ||
To release a new version | ||
1. Create a [new GitHub Release](https://github.com/samchungy/zod-openapi/releases/new) | ||
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](https://github.com/samchungy/zod-openapi/releases/new) | ||
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. | ||
## Comparisons | ||
### [@asteasolutions/zod-to-openapi](https://github.com/asteasolutions/zod-to-openapi) | ||
@@ -544,6 +507,4 @@ | ||
4. No native `yaml` support. The majority of my projects prefer to render the schema in `yaml` so I would have to install an extra dependency. This library ships it natively. | ||
4. Eslint rules. I initially created some rules for that library, however, I had to add some awkward logic to account for the registry class. With more creative control, I can create better rules going forward. See [eslint-plugin-zod-openapi](https://github.com/samchungy/eslint-plugin-zod-openapi) for some magic. | ||
5. Eslint rules. I initially created some rules for that library, however, I had to add some awkward logic to account for the registry class. With more creative control, I can create better rules going forward. See [eslint-plugin-zod-openapi](https://github.com/samchungy/eslint-plugin-zod-openapi) for some magic. | ||
Did I really rewrite an entire library just for this? Absolutely. I believe that creating documentation and types should be as simple and as frictionless as possible. | ||
@@ -646,1 +607,46 @@ | ||
``` | ||
## Development | ||
### Prerequisites | ||
- Node.js LTS | ||
- Yarn 1.x | ||
```shell | ||
yarn install | ||
``` | ||
### Test | ||
```shell | ||
yarn test | ||
``` | ||
### Lint | ||
```shell | ||
# Fix issues | ||
yarn format | ||
# Check for issues | ||
yarn lint | ||
``` | ||
### Release | ||
To release a new version | ||
1. Create a [new GitHub Release](https://github.com/samchungy/zod-openapi/releases/new) | ||
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](https://github.com/samchungy/zod-openapi/releases/new) | ||
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. |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
281301
647