Библиотека Typescript для использования схем Zod для создания документации OpenAPI v3.x.
Установите через npm
, yarn
или pnpm
:
npm install zod zod-openapi
# # or
yarn add zod zod-openapi
# # or
pnpm install zod zod-openapi
Это мутирует Zod, добавляя дополнительный метод .openapi()
. Вызовите это в верхней части точки входа. Вы можете добиться этого двумя разными способами, в зависимости от ваших предпочтений.
import 'zod-openapi/extend' ;
import { z } from 'zod' ;
z . string ( ) . openapi ( { description : 'hello world!' , example : 'hello world' } ) ;
Это полезно, если у вас есть конкретный экземпляр Zod или экземпляр Zod из другой библиотеки, на который вы хотите настроить таргетинг.
import { z } from 'zod' ;
import { extendZodWithOpenApi } from 'zod-openapi' ;
extendZodWithOpenApi ( z ) ;
z . string ( ) . openapi ( { description : 'hello world!' , example : 'hello world' } ) ;
.openapi()
Используйте метод .openapi()
для добавления метаданных к определенному типу Zod. Метод .openapi()
принимает объект со следующими параметрами:
Вариант | Описание |
---|---|
Параметры OpenAPI | При этом будет использоваться любой параметр, который вы поместили бы в SchemaObject. |
effectType | Используйте, чтобы переопределить тип создания для эффекта Зода. |
header | Используйте для предоставления метаданных для заголовков ответов. |
param | Используйте для предоставления метаданных для параметров запроса. |
ref | Используйте это для автоматической регистрации схемы как компонента многократного использования. |
refType | Используйте это, чтобы установить тип создания компонента, на который нет ссылки в документе. |
type | Используйте это, чтобы переопределить сгенерированный тип. Если это предусмотрено, метаданные генерироваться не будут. |
unionOneOf | Установите значение true , чтобы заставить один ZodUnion выводить oneOf вместо anyOf . См. CreateDocumentOptions для глобальной опции. |
createDocument
Создает объект документации OpenAPI.
import 'zod-openapi/extend' ;
import { z } from 'zod' ;
import { createDocument } from 'zod-openapi' ;
const jobId = z . string ( ) . openapi ( {
description : 'A unique identifier for a job' ,
example : '12345' ,
ref : 'jobId' ,
} ) ;
const title = z . string ( ) . openapi ( {
description : 'Job title' ,
example : '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 } ) } ,
} ,
} ,
} ,
} ,
} ,
} ,
} ) ;
{
"openapi" : " 3.1.0 " ,
"info" : {
"title" : " My API " ,
"version" : " 1.0.0 "
},
"paths" : {
"/jobs/{jobId}" : {
"put" : {
"parameters" : [
{
"in" : " path " ,
"name" : " jobId " ,
"description" : " A unique identifier for a job " ,
"schema" : {
"$ref" : " #/components/schemas/jobId "
}
}
],
"requestBody" : {
"content" : {
"application/json" : {
"schema" : {
"type" : " object " ,
"properties" : {
"title" : {
"type" : " string " ,
"description" : " Job title " ,
"example" : " My job "
}
},
"required" : [ " title " ]
}
}
}
},
"responses" : {
"200" : {
"description" : " 200 OK " ,
"content" : {
"application/json" : {
"schema" : {
"type" : " object " ,
"properties" : {
"jobId" : {
"$ref" : " #/components/schemas/jobId "
},
"title" : {
"type" : " string " ,
"description" : " Job title " ,
"example" : " My job "
}
},
"required" : [ " jobId " , " title " ]
}
}
}
}
}
}
}
},
"components" : {
"schemas" : {
"jobId" : {
"type" : " string " ,
"description" : " A unique identifier for a job " ,
"example" : " 12345 "
}
}
}
}
createDocument
принимает необязательный аргумент CreateDocumentOptions
, который можно использовать для изменения способа создания документа.
const document = createDocument ( details , {
defaultDateSchema : { type : 'string' , format : 'date-time' } , // defaults to { type: 'string' }
unionOneOf : true , // defaults to false. Forces all ZodUnions to output oneOf instead of anyOf. An `.openapi()` `unionOneOf` value takes precedence over this one.
} ) ;
createSchema
Создает объект схемы OpenAPI вместе со всеми зарегистрированными компонентами. Объекты схемы OpenAPI 3.1.0 полностью совместимы со схемой JSON.
import 'zod-openapi/extend' ;
import { z } from 'zod' ;
import { createSchema } from 'zod-openapi' ;
const jobId = z . string ( ) . openapi ( {
description : 'A unique identifier for a job' ,
example : '12345' ,
ref : 'jobId' ,
} ) ;
const title = z . string ( ) . openapi ( {
description : 'Job title' ,
example : 'My job' ,
} ) ;
const job = z . object ( {
jobId ,
title ,
} ) ;
const { schema , components } = createSchema ( job ) ;
{
"schema" : {
"type" : " object " ,
"properties" : {
"jobId" : {
"$ref" : " #/components/schemas/jobId "
},
"title" : {
"type" : " string " ,
"description" : " Job title " ,
"example" : " My job "
}
},
"required" : [ " jobId " , " title " ]
},
"components" : {
"jobId" : {
"type" : " string " ,
"description" : " A unique identifier for a job " ,
"example" : " 12345 "
}
}
}
createSchema
принимает необязательный параметр CreateSchemaOptions
, который также может принимать те же параметры, что и CreateDocumentOptions, а также следующие параметры:
const { schema , components } = createSchema ( job , {
schemaType : 'input' ; // This controls whether this should be rendered as a request (`input`) or response (`output`). Defaults to `output`
openapi: '3.0.0' ; // OpenAPI version to use, defaults to `'3.1.0'`
components: { jobId : z . string ( ) } // Additional components to use and create while rendering the schema
componentRefPath: '#/definitions/' // Defaults to #/components/schemas/
} )
Параметры запроса, пути, заголовка и cookie можно создать с помощью ключа requestParams
под ключом method
следующим образом:
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 ( ) } ) ,
} ,
} ,
} ,
} ,
} ) ;
Если вы хотите объявить параметры более традиционным способом, вы также можете объявить их с помощью ключа параметров. Затем все определения будут объединены.
createDocument ( {
paths : {
'/jobs/{a}' : {
put : {
parameters : [
z . string ( ) . openapi ( {
param : {
name : 'job-header' ,
in : 'header' ,
} ,
} ) ,
] ,
} ,
} ,
} ,
} ) ;
Там, где вы обычно объявляете тип носителя, установите schema
в качестве схемы Zod следующим образом.
createDocument ( {
paths : {
'/jobs' : {
get : {
requestBody : {
content : {
'application/json' : { schema : z . object ( { a : z . string ( ) } ) } ,
} ,
} ,
} ,
} ,
} ,
} ) ;
Если вы хотите использовать синтаксис OpenAPI для своих схем, просто добавьте вместо этого схему OpenAPI в поле schema
.
Как и в случае с телом запроса, просто установите schema
в качестве схемы Zod следующим образом. Вы можете установить заголовки ответов, используя ключ headers
.
createDocument ( {
paths : {
'/jobs' : {
get : {
responses : {
200 : {
description : '200 OK' ,
content : {
'application/json' : { schema : z . object ( { a : z . string ( ) } ) } ,
} ,
headers : z . object ( {
'header-key' : z . string ( ) ,
} ) ,
} ,
} ,
} ,
} ,
} ,
} ) ;
createDocument ( {
paths : {
'/jobs' : {
get : {
callbacks : {
onData : {
'{$request.query.callbackUrl}/data' : {
post : {
requestBody : {
content : {
'application/json' : { schema : z . object ( { a : z . string ( ) } ) } ,
} ,
} ,
responses : {
200 : {
description : '200 OK' ,
content : {
'application/json' : {
schema : z . object ( { a : z . string ( ) } ) ,
} ,
} ,
} ,
} ,
} ,
} ,
} ,
} ,
} ,
} ,
} ,
} ) ;
OpenAPI позволяет определять повторно используемые компоненты, а эта библиотека позволяет воспроизводить это двумя разными способами.
Если мы возьмем пример из createDocument
и вместо этого создадим title
следующим образом:
const title = z . string ( ) . openapi ( {
description : 'Job title' ,
example : 'My job' ,
ref : 'jobTitle' , // <- new field
} ) ;
Везде, где title
используется в схемах документа, вместо этого он будет создан как ссылка.
{ "$ref" : " #/components/schemas/jobTitle " }
title
будет выведен в виде схемы в разделе компонентов документации.
{
"components" : {
"schemas" : {
"jobTitle" : {
"type" : " string " ,
"description" : " Job title " ,
"example" : " My job "
}
}
}
}
Это может быть чрезвычайно эффективным способом создания менее повторяющейся документации Open API. Существуют некоторые функции Open API, такие как сопоставление дискриминаторов, которые требуют, чтобы все схемы в объединении содержали ссылку.
Другой способ зарегистрировать схему вместо добавления ref
— добавить ее напрямую к компонентам. Это по-прежнему будет работать так же, как ref
. Поэтому всякий раз, когда мы сталкиваемся с этим типом Zod, мы заменяем его ссылкой.
например.
createDocument ( {
components : {
schemas : {
jobTitle : title , // this will register this Zod Schema as jobTitle unless `ref` in `.openapi()` is specified on the type
} ,
} ,
} ) ;
К сожалению, в качестве ограничения этой библиотеки вам нужно будет прикрепить поле .openapi()
или .describe()
к схеме, которую вы передаете в компоненты, иначе вы не сможете получить всю мощь генерации компонентов. В результате я рекомендую использовать компоненты автоматической регистрации вместо ручной регистрации.
Параметры запроса, пути, заголовка и cookie могут быть зарегистрированы аналогичным образом:
// Easy auto registration
const jobId = z . string ( ) . openapi ( {
description : 'Job ID' ,
example : '1234' ,
param : { ref : 'jobRef' } ,
} ) ;
createDocument ( {
paths : {
'/jobs/{jobId}' : {
put : {
requestParams : {
header : z . object ( {
jobId ,
} ) ,
} ,
} ,
} ,
} ,
} ) ;
// or more verbose auto registration
const jobId = z . string ( ) . openapi ( {
description : 'Job ID' ,
example : '1234' ,
param : { in : 'header' , name : 'jobId' , ref : 'jobRef' } ,
} ) ;
createDocument ( {
paths : {
'/jobs/{jobId}' : {
put : {
parameters : [ jobId ] ,
} ,
} ,
} ,
} ) ;
// or manual registeration
const otherJobId = z . string ( ) . openapi ( {
description : 'Job ID' ,
example : '1234' ,
param : { in : 'header' , name : 'jobId' } ,
} ) ;
createDocument ( {
components : {
parameters : {
jobRef : jobId ,
} ,
} ,
} ) ;
Заголовки ответов можно зарегистрировать аналогичным образом:
const header = z . string ( ) . openapi ( {
description : 'Job ID' ,
example : '1234' ,
header : { ref : 'some-header' } ,
} ) ;
// or
const jobIdHeader = z . string ( ) . openapi ( {
description : 'Job ID' ,
example : '1234' ,
} ) ;
createDocument ( {
components : {
headers : {
someHeaderRef : jobIdHeader ,
} ,
} ,
} ) ;
Также можно зарегистрировать целые ответы.
const response : ZodOpenApiResponseObject = {
description : '200 OK' ,
content : {
'application/json' : {
schema : z . object ( { a : z . string ( ) } ) ,
} ,
} ,
ref : 'some-response' ,
} ;
//or
const response : ZodOpenApiResponseObject = {
description : '200 OK' ,
content : {
'application/json' : {
schema : z . object ( { a : z . string ( ) } ) ,
} ,
} ,
} ;
createDocument ( {
components : {
responses : {
'some-response' : response ,
} ,
} ,
} ) ;
Обратные вызовы также можно зарегистрировать.
const callback : ZodOpenApiCallbackObject = {
ref : 'some-callback'
post : {
responses : {
200 : {
description : '200 OK' ,
content : {
'application/json' : {
schema : z . object ( { a : z . string ( ) } ) ,
}