fastify-type-provider-typebox

repository·main·Indexed 41 days ago

https://github.com/fastify/fastify-type-provider-typebox

A Type Provider for TypeBox over Fastify (version 6.1.0) that enables seamless type inference for request bodies, queries, and responses in TypeScript and JavaScript projects. It integrates TypeBox with Fastify's Type Provider infrastructure and includes the TypeBoxValidatorCompiler for high-performance runtime type checking and automatic value conversion.

Tokens
3.6K
Snippets
14
Records
15
Agent score
3%

What's inside fastify-type-provider-typebox

  1. Initialize Fastify with TypeBox Type Provider

    main

    To enable type inference for your routes, you must call .withTypeProvider<TypeBoxTypeProvider>() immediately after initializing Fastify.

    Important: You cannot call .withTypeProvider() on an existing Fastify instance; it must be chained during initialization.

    import Fastify from 'fastify'
    import { Type, TypeBoxTypeProvider } from '@fastify/type-provider-typebox'
    
    const fastify = Fastify().withTypeProvider<TypeBoxTypeProvider>()
  2. Register standard string formats (date, date-time, etc.)

    main

    When using the TypeBoxValidatorCompiler, standard string formats like date or date-time are not registered by default. You must register them explicitly using registerAjvFormats (or similar utility) to ensure they are validated correctly.

    import { registerAjvFormats } from '@fastify/type-provider-typebox'
    
    registerAjvFormats()
  3. Use TypeBox with JavaScript and JSDoc

    main

    For plain JavaScript projects using checkJs, you can apply the type provider using JSDoc type casts.

    For a Fastify Instance:

    /** @typedef {import('fastify').FastifyInstance<import('fastify').RawServerDefault, import('fastify').RawRequestDefaultExpression, import('fastify').RawReplyDefaultExpression, import('fastify').FastifyBaseLogger, import('@fastify/type-provider-typebox').TypeBoxTypeProvider>} FastifyTypeBox */
    
    const fastify = /** @type {FastifyTypeBox} */ (Fastify())

    For Plugins:

    /** @type {import('@fastify/type-provider-typebox').FastifyPluginAsyncTypebox} */
    const plugin = async (fastify) => {
      // routes registered here get full type inference
    }
    import Fastify from 'fastify'
    import { Type } from '@fastify/type-provider-typebox'
    
    /** @typedef {import('fastify').FastifyInstance<import('fastify').RawServerDefault, import('fastify').RawRequestDefaultExpression, import('fastify').RawReplyDefaultExpression, import('fastify').FastifyBaseLogger, import('@fastify/type-provider-typebox').TypeBoxTypeProvider>} FastifyTypeBox */
    
    const fastify = /** @type {FastifyTypeBox} */ (Fastify())
    
    fastify.post('/', {
      schema: {
        body: Type.Object({ x: Type.String() })
      }
    }, (req) => {
      const { x } = req.body // inferred as string
    })
  4. Example: Using TypeBox for route schema and inference

    main

    This example demonstrates how to define a route schema using the re-exported Type builder and how the request body types are automatically inferred in the handler.

    import Fastify from 'fastify'
    import { TypeBoxTypeProvider } from '@fastify/type-provider-typebox'
    
    // This package re-export Typebox package
    // but you can also use any builders imported
    // directly from typebox
    import { Type } from 'typebox'
    
    
    const fastify = Fastify().withTypeProvider<TypeBoxTypeProvider>()
    
    fastify.post('/', {
      schema: {
        body: Type.Object({
          x: Type.String(),
          y: Type.Number(),
          z: Type.Boolean()
        })
      }
    }, (req) => {
      // The `x`, `y`, `z` types are automatically inferred
      const { x, y, z } = req.body
    })
  5. Define TypeBox plugins

    main

    When defining a plugin using FastifyPluginAsyncTypebox, you do not need to call .withTypeProvider() inside the plugin to get full type inference for routes registered within it.

    import { Type, FastifyPluginAsyncTypebox } from '@fastify/type-provider-typebox'
    
    const plugin: FastifyPluginAsyncTypebox = async function(fastify, _opts) {
      fastify.get('/', {
        schema: {
          body: Type.Object({
            x: Type.String(),
            y: Type.Number(),
            z: Type.Boolean()
          })
        }
      }, (req) => {
        /// The `x`, `y`, and `z` types are automatically inferred
        const { x, y, z } = req.body
      });
    }
  6. Enable the TypeBox Validator Compiler

    main

    To perform high-performance runtime type checking, you can enable the TypeBox compiler by passing TypeBoxValidatorCompiler to .setValidatorCompiler(). This compiler is limited to types expressible through the TypeBox Type.* namespace.

    import { Type, TypeBoxTypeProvider, TypeBoxValidatorCompiler } from '@fastify/type-provider-typebox'
    import Fastify from 'fastify'
    
    const fastify = Fastify().setValidatorCompiler(TypeBoxValidatorCompiler)
    
    fastify.withTypeProvider<TypeBoxTypeProvider>().get('/', {
      schema: {
        querystring: Type.Object({
          x: Type.String(),
          y: Type.String(),
          z: Type.String()
        })
      }
    }, (req) => {
      const { x, y, z } = req.query
    })
  7. Use TypeBox types for FastifyRequest and FastifyReply

    main

    When you need to manually type your route handlers (e.g., when extracting them from the main file), use FastifyRequestTypeBox and FastifyReplyTypeBox. These types accept a schema as a generic to provide full inference for req.body, req.query, etc.

    import type { TypeBoxTypeProvider } from '@fastify/type-provider-typebox';
    import { Type } from '@fastify/type-provider-typebox';
    import type {
      ContextConfigDefault,
      FastifyBaseLogger,
      FastifyInstance,
      FastifyReply,
      FastifyRequest,
      RawReplyDefaultExpression,
      RawRequestDefaultExpression,
      RawServerDefault,
    } from 'fastify';
    import type { RouteGenericInterface } from 'fastify/types/route';
    import type { FastifySchema } from 'fastify/types/schema';
    
    export type FastifyTypeBox = FastifyInstance<
      RawServerDefault,
      RawRequestDefaultExpression,
      RawReplyDefaultExpression,
      FastifyBaseLogger,
      TypeBoxTypeProvider
    >;
    
    export type FastifyRequestTypeBox<TSchema extends FastifySchema> = FastifyRequest<
      RouteGenericInterface,
      RawServerDefault,
      RawRequestDefaultExpression,
      TSchema,
      TypeBoxTypeProvider
    >;
    
    export type FastifyReplyTypeBox<TSchema extends FastifySchema> = FastifyReply<
      RouteGenericInterface,
      RawServerDefault,
      RawRequestDefaultExpression,
      RawReplyDefaultExpression,
      ContextConfigDefault,
      TSchema,
      TypeBoxTypeProvider
    >;
    
    export const CreateProductSchema = {
      body: Type.Object({
        name: Type.String(),
        price: Type.Number(),
      }),
      response: {
        201: Type.Object({
          id: Type.Number(),
        }),
      },
    };
    
    export const CreateProductHandler = (
      req: FastifyRequestTypeBox<typeof CreateProductSchema>,
      reply: FastifyReplyTypeBox<typeof CreateProductSchema>,
    ) => {
      // The `name` and `price` types are automatically inferred
      const { name, price } = req.body;
    
      // The response body type is automatically inferred
      reply.status(201).send({ id: 'string-value' });
      //                       ^? error TS2322: Type 'string' is not assignable to type 'number'.
    };
  8. Check compatibility with Fastify

    main

    Ensure your Fastify version is compatible with the installed plugin version:

    Plugin versionFastify version
    >=5.x^5.x
    >=1.x <5.x^4.x

    Note that if a Fastify version is out of support, the corresponding plugin versions are also out of support.

    | Plugin version | Fastify version |
    | ---------------|-----------------|
    | `>=5.x`        | `^5.x`          |
    | `>=1.x <5.x`   | `^4.x`          |
  9. Enable automatic type inference with TypeBoxTypeProvider

    main

    To enable automatic type inference for your routes (allowing TypeScript to know the shape of request.body, request.query, etc., based on your TypeBox schemas), use the TypeBoxTypeProvider interface with the .withTypeProvider<T>() method on your Fastify instance.

    import Fastify from 'fastify'
    import { TypeBoxTypeProvider } from '@fastify/type-provider-typebox'
    
    const server = Fastify().withTypeProvider<TypeBoxTypeProvider>()
  10. Use TypeBox-enabled plugin types

    main

    When writing Fastify plugins that should benefit from TypeBox type inference, use the specialized plugin types provided by the package. This ensures the fastify instance passed to your plugin is correctly typed with TypeBoxTypeProvider.

    Available types:

    • FastifyPluginAsyncTypebox: For async plugins.
    • FastifyPluginCallbackTypebox: For callback-based plugins.
    import { FastifyPluginAsyncTypebox } from '@fastify/type-provider-typebox'
    
    const plugin: FastifyPluginAsyncTypebox = async (fastify, options) => {
      // fastify is typed with TypeBoxTypeProvider here
    }