Eine Typescript-Bibliothek zur Verwendung von Zod-Schemas zum Erstellen von OpenAPI v3.x-Dokumentation
Installation über npm
, yarn
oder pnpm
:
npm install zod zod-openapi
# # or
yarn add zod zod-openapi
# # or
pnpm install zod zod-openapi
Dies mutiert Zod, um eine zusätzliche .openapi()
-Methode hinzuzufügen. Rufen Sie dies oben an Ihrem/Ihren Einstiegspunkt(en) auf. Dies können Sie je nach Wunsch auf zwei verschiedene Arten erreichen.
import 'zod-openapi/extend' ;
import { z } from 'zod' ;
z . string ( ) . openapi ( { description : 'hello world!' , example : 'hello world' } ) ;
Dies ist nützlich, wenn Sie eine bestimmte Instanz von Zod oder eine Zod-Instanz aus einer anderen Bibliothek haben, auf die Sie abzielen möchten.
import { z } from 'zod' ;
import { extendZodWithOpenApi } from 'zod-openapi' ;
extendZodWithOpenApi ( z ) ;
z . string ( ) . openapi ( { description : 'hello world!' , example : 'hello world' } ) ;
.openapi()
Verwenden Sie die Methode .openapi()
um Metadaten zu einem bestimmten Zod-Typ hinzuzufügen. Die Methode .openapi()
akzeptiert ein Objekt mit den folgenden Optionen:
Option | Beschreibung |
---|---|
OpenAPI-Optionen | Dies erfordert jede Option, die Sie einem SchemaObject hinzufügen würden. |
effectType | Wird verwendet, um den Erstellungstyp für einen Zod-Effekt zu überschreiben |
header | Wird verwendet, um Metadaten für Antwortheader bereitzustellen |
param | Wird verwendet, um Metadaten für Anforderungsparameter bereitzustellen |
ref | Verwenden Sie dies, um ein Schema automatisch als wiederverwendbare Komponente zu registrieren |
refType | Verwenden Sie diese Option, um den Erstellungstyp für eine Komponente festzulegen, auf die im Dokument nicht verwiesen wird. |
type | Verwenden Sie dies, um den generierten Typ zu überschreiben. Wenn dies angegeben ist, werden keine Metadaten generiert. |
unionOneOf | Auf true setzen, um zu erzwingen, dass eine einzelne ZodUnion oneOf anstelle von anyOf ausgibt. Eine globale Option finden Sie unter CreateDocumentOptions |
createDocument
Erstellt ein OpenAPI-Dokumentationsobjekt
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
akzeptiert ein optionales CreateDocumentOptions
-Argument, mit dem geändert werden kann, wie das Dokument erstellt wird.
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
Erstellt ein OpenAPI-Schemaobjekt zusammen mit allen registrierten Komponenten. OpenAPI 3.1.0-Schemaobjekte sind vollständig mit dem JSON-Schema kompatibel.
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
verwendet einen optionalen Parameter CreateSchemaOptions
der neben den folgenden Optionen auch dieselben Optionen wie „CreateDocumentOptions“ annehmen kann:
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/
} )
Abfrage-, Pfad-, Header- und Cookie-Parameter können mit dem Schlüssel requestParams
unter dem method
wie folgt erstellt werden:
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 ( ) } ) ,
} ,
} ,
} ,
} ,
} ) ;
Wenn Sie Parameter auf traditionellere Weise deklarieren möchten, können Sie sie auch mit dem Parameterschlüssel deklarieren. Die Definitionen werden dann alle zusammengefasst.
createDocument ( {
paths : {
'/jobs/{a}' : {
put : {
parameters : [
z . string ( ) . openapi ( {
param : {
name : 'job-header' ,
in : 'header' ,
} ,
} ) ,
] ,
} ,
} ,
} ,
} ) ;
Wo Sie normalerweise den Medientyp deklarieren würden, legen Sie das schema
wie folgt als Ihr Zod-Schema fest.
createDocument ( {
paths : {
'/jobs' : {
get : {
requestBody : {
content : {
'application/json' : { schema : z . object ( { a : z . string ( ) } ) } ,
} ,
} ,
} ,
} ,
} ,
} ) ;
Wenn Sie die OpenAPI-Syntax für Ihre Schemata verwenden möchten, fügen Sie stattdessen einfach ein OpenAPI-Schema zum schema
hinzu.
Legen Sie, ähnlich wie beim Anforderungstext, einfach das schema
wie folgt als Ihr Zod-Schema fest. Sie können die Antwortheader mit der headers
-Taste festlegen.
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 ( ) } ) ,
} ,
} ,
} ,
} ,
} ,
} ,
} ,
} ,
} ,
} ,
} ,
} ) ;
Mit OpenAPI können Sie wiederverwendbare Komponenten definieren und mit dieser Bibliothek können Sie dies auf zwei verschiedene Arten replizieren.
Nehmen wir das Beispiel in createDocument
und erstellen stattdessen title
wie folgt
const title = z . string ( ) . openapi ( {
description : 'Job title' ,
example : 'My job' ,
ref : 'jobTitle' , // <- new field
} ) ;
Wo immer title
in Schemata im gesamten Dokument verwendet wird, wird er stattdessen als Referenz erstellt.
{ "$ref" : " #/components/schemas/jobTitle " }
title
wird dann als Schema im Abschnitt „Komponenten“ der Dokumentation ausgegeben.
{
"components" : {
"schemas" : {
"jobTitle" : {
"type" : " string " ,
"description" : " Job title " ,
"example" : " My job "
}
}
}
}
Dies kann eine äußerst leistungsstarke Möglichkeit sein, eine weniger repetitive Open-API-Dokumentation zu erstellen. Es gibt einige Open-API-Funktionen wie die Diskriminatorzuordnung, die erfordern, dass alle Schemas in der Union einen Verweis enthalten.
Eine andere Möglichkeit, ein Schema zu registrieren, anstatt eine ref
hinzuzufügen, besteht darin, es direkt zu den Komponenten hinzuzufügen. Dies funktioniert immer noch auf die gleiche Weise wie ref
. Wenn wir also auf diesen Zod-Typ stoßen, ersetzen wir ihn durch eine Referenz.
z.B.
createDocument ( {
components : {
schemas : {
jobTitle : title , // this will register this Zod Schema as jobTitle unless `ref` in `.openapi()` is specified on the type
} ,
} ,
} ) ;
Als Einschränkung dieser Bibliothek müssen Sie leider ein .openapi()
Feld oder .describe()
an das Schema anhängen, das Sie an die Komponenten übergeben, sonst erhalten Sie möglicherweise nicht die volle Leistungsfähigkeit der Komponentengenerierung. Daher empfehle ich die Verwendung der automatischen Registrierungskomponenten gegenüber der manuellen Registrierung.
Abfrage-, Pfad-, Header- und Cookie-Parameter können auf ähnliche Weise registriert werden:
// 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 ,
} ,
} ,
} ) ;
Antwortheader können auf ähnliche Weise registriert werden:
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 ,
} ,
} ,
} ) ;
Es können auch vollständige Antworten registriert werden
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 ,
} ,
} ,
} ) ;
Auch Rückrufe können angemeldet werden
const callback : ZodOpenApiCallbackObject = {
ref : 'some-callback'
post : {
responses : {
200 : {
description : '200 OK' ,
content : {
'application/json' : {
schema : z . object ( { a : z . string ( ) } ) ,
}