UNPKG

@fastify/type-provider-json-schema-to-ts

Version:
264 lines (229 loc) 7.49 kB
# @fastify/type-provider-json-schema-to-ts [![CI](https://github.com/fastify/fastify-type-provider-json-schema-to-ts/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/fastify/fastify-type-provider-json-schema-to-ts/actions/workflows/ci.yml) [![NPM version](https://img.shields.io/npm/v/@fastify/type-provider-json-schema-to-ts.svg?style=flat)](https://www.npmjs.com/package/@fastify/type-provider-json-schema-to-ts) [![neostandard javascript style](https://img.shields.io/badge/code_style-neostandard-brightgreen?style=flat)](https://github.com/neostandard/neostandard) A Type Provider for [json-schema-to-ts](https://github.com/ThomasAribart/json-schema-to-ts) ## Install ```bash npm i @fastify/type-provider-json-schema-to-ts ``` ## TypeScript requirements It is required to use `TypeScript@4.3` or above with [`strict`](https://www.typescriptlang.org/tsconfig#strict) mode enabled and [`noStrictGenericChecks`](https://www.typescriptlang.org/tsconfig#noStrictGenericChecks) disabled. You may take the following configuration (`tsconfig.json`) as an example: ```json { "compilerOptions": { "strict": true, "noStrictGenericChecks": false } } ``` ## Plugin definition > **Note** > When using plugin types, `withTypeProvider` is not required to register the plugin. ```ts const plugin: FastifyPluginAsyncJsonSchemaToTs = async function ( fastify, _opts ) { fastify.get( "/", { schema: { body: { type: "object", properties: { x: { type: "string" }, y: { type: "number" }, z: { type: "boolean" }, }, required: ["x", "y", "z"], } as const, }, }, (req) => { // The `x`, `y`, and `z` types are automatically inferred const { x, y, z } = req.body; } ); }; ``` ## Setting FromSchema for the validator and serializer You can set the `FromSchema` settings for things like [`references`](https://github.com/ThomasAribart/json-schema-to-ts#references) and [`deserialization`](https://github.com/ThomasAribart/json-schema-to-ts#deserialization) for the validation and serialization schema by setting `ValidatorSchemaOptions` and `SerializerSchemaOptions` type parameters. You can use the `deserialize` option in `SerializerSchemaOptions` to allow Date objects in place of date-time strings or other special serialization rules handled by [fast-json-stringify](https://github.com/fastify/fast-json-stringify?tab=readme-ov-file#specific-use-cases). ```ts const userSchema = { type: "object", additionalProperties: false, properties: { givenName: { type: "string" }, familyName: { type: "string" }, }, required: ["givenName", "familyName"], } as const satisfies JSONSchema; const sharedSchema = { $id: "shared-schema", definitions: { user: userSchema, }, } as const satisfies JSONSchema; const userProfileSchema = { $id: "userProfile", type: "object", additionalProperties: false, properties: { user: { $ref: "shared-schema#/definitions/user", }, joinedAt: { type: "string", format: "date-time" }, }, required: ["user", "joinedAt"], } as const satisfies JSONSchema type UserProfile = FromSchema<typeof userProfileSchema, { references: [typeof sharedSchema] deserialize: [{ pattern: { type: "string"; format: "date-time" }; output: Date }] }>; // Use JsonSchemaToTsProvider with shared schema references const fastify = Fastify().withTypeProvider< JsonSchemaToTsProvider<{ ValidatorSchemaOptions: { references: [typeof sharedSchema] } }> >(); const fastify = Fastify().withTypeProvider< JsonSchemaToTsProvider<{ ValidatorSchemaOptions: { references: [typeof sharedSchema] } SerializerSchemaOptions: { references: [typeof userProfileSchema] deserialize: [{ pattern: { type: "string"; format: "date-time" }; output: Date }] } }> >() fastify.get( "/profile", { schema: { body: { type: "object", properties: { user: { $ref: "shared-schema#/definitions/user", }, }, required: ['user'], }, response: { 200: { $ref: "userProfile#" }, }, } as const, }, (req, reply) => { // `givenName` and `familyName` are correctly typed as strings const { givenName, familyName } = req.body.user; // Construct a compatible response type const profile: UserProfile = { user: { givenName: "John", familyName: "Doe" }, joinedAt: new Date(), // Returning a Date object }; // A type error is surfaced if profile doesn't match the serialization schema reply.send(profile) } ) ``` ## Using References in a Plugin Definition When defining a plugin, shared schema references and deserialization options can also be used with `FastifyPluginAsyncJsonSchemaToTs` and `FastifyPluginCallbackJsonSchemaToTs`. ### Example ```ts const schemaPerson = { $id: "schema:person", type: "object", additionalProperties: false, properties: { givenName: { type: "string" }, familyName: { type: "string" }, joinedAt: { type: "string", format: "date-time" }, }, required: ["givenName", "familyName"], } as const satisfies JSONSchema; const plugin: FastifyPluginAsyncJsonSchemaToTs<{ ValidatorSchemaOptions: { references: [typeof schemaPerson] } SerializerSchemaOptions: { references: [typeof schemaPerson] deserialize: [{ pattern: { type: "string"; format: "date-time" }; output: Date }] }; }> = async function (fastify, _opts) { fastify.addSchema(schemaPerson) fastify.get( "/profile", { schema: { body: { type: "object", properties: { user: { $ref: "schema:person", }, }, required: ['user'], }, response: { 200: { $ref: "schema:person" }, }, }, // as const satisfies JSONSchema is not required thanks to FastifyPluginAsyncJsonSchemaToTs }, (req, reply) => { // `givenName`, `familyName`, and `joinedAt` are correctly typed as strings and validated for format. const { givenName, familyName, joinedAt } = req.body.user; // Send a serialized response reply.send({ givenName: "John", familyName: "Doe", // Date objects form DB queries can be returned directly and transformed to string by fast-json-stringify joinedAt: new Date(), }) } ) } const callbackPlugin: FastifyPluginCallbackJsonSchemaToTs<{ ValidatorSchemaOptions: { references: [typeof schemaPerson] } SerializerSchemaOptions: { references: [typeof schemaPerson] deserialize: [{ pattern: { type: "string"; format: "date-time" }; output: Date }] }; }> = (fastify, options, done) => { // Type check for custom options expectType<string>(options.optionA) // Schema is already added above // fastify.addSchema(schemaPerson); fastify.get( "/callback-profile", { schema: { body: { type: "object", properties: { user: { $ref: "schema:person" }, }, required: ["user"], }, response: { 200: { $ref: "schema:person" }, }, }, }, (req, reply) => { const { givenName, familyName, joinedAt } = req.body.user reply.send({ givenName, familyName, joinedAt: new Date(), }); } ); done() }; ```