ts-rest

website·Indexed 33 days ago

https://ts-rest.com

A library for defining type-safe API contracts between servers and clients. It provides a core contract system and integrations for servers including Express, Fastify, NestJS, Next.js, and various serverless runtimes (AWS Lambda, Azure Functions), as well as clients for React Query (v4 and v5), Vue Query (v4), and Fetch. Includes support for generating OpenAPI documentation via @ts-rest/open-api.

Tokens
23.4K
Snippets
122
Records
182
Agent score
69%

What's inside ts-rest

  1. Use ts-rest with WinterCG compatible Fetch Runtimes

    The @ts-rest/serverless/fetch handler is compatible with any runtime that follows the WinterCG Minimum Common Web Platform API. This includes Cloudflare Workers, Netlify Functions, and Vercel Functions.
  2. Support for multipart/form-data

    Support for multipart/form-data is implemented across core, express, nest, react-query, and solid-query packages.
  3. Define an API contract with ts-rest

    The contract is the core of ts-rest, defining the API specification that both the server and client adhere to. This ensures type-safety across the stack. Contracts are typically placed in a shared location (e.g., a shared module in a monorepo or an external package) so both the server and client can import them.
  4. Migrate from initNextClient to initClient in @ts-rest/next

    The initNextClient function is deprecated. Developers should now use initClient from @ts-rest/core and provide Next.js-specific configurations via the fetchOptions.next parameter.
    // Instead of initNextClient, use:
    import { initClient } from '@ts-rest/core';
    
    const client = initClient({
      baseUrl: 'https://api.example.com',
      fetchOptions: {
        next: { revalidate: 60 } // Next.js specific options here
      }
    });
  5. Support for Next.js App Router in serverless

    The @ts-rest/serverless package now supports Next.js App Router route handlers.
  6. Enable server-side response validation

    Version 3.16.0 introduced a server-side response validation feature. This is supported across the core, express, nest, and next packages to ensure that the data returned by the server matches the defined API contract.
  7. Install @ts-rest/nest

    Install the NestJS integration package for ts-rest using your preferred package manager.
    # Using pnpm
    pnpm add @ts-rest/nest
    
    # Using bun
    bun add @ts-rest/nest
    
    # Using npm
    npm install @ts-rest/nest
  8. Implement a ts-rest handler for AWS Lambda

    Use createLambdaHandler from @ts-rest/serverless/aws to create a Lambda handler that is compatible with both API Gateway v1 and v2 events. The handler requires the contract and the router implementation.
    import { createLambdaHandler } from '@ts-rest/serverless/aws';
    import { contract } from './contract';
    import { router } from './router';
    
    export const handler = createLambdaHandler(contract, router, {
      // options
    });
  9. Implement a custom API fetcher for interceptors

    To implement request/response interceptors or custom error handling, provide a custom api function to initClient. You can wrap the default tsRestFetchApi implementation to add logic before and after the request.
    import { initClient, tsRestFetchApi, ApiFetcherArgs } from '@ts-rest/core';
    import { contract } from './contract';
    
    const client = initClient(contract, {
      baseUrl: 'https://api.example.com',
      api: async (args: ApiFetcherArgs) => {
        // Request Interceptor: Add logging
        console.log(`Making ${args.method} request to ${args.path}`);
    
        // Call the default implementation
        const result = await tsRestFetchApi(args);
    
        // Response Interceptor
        console.log(`Response: ${result.status}`);
        return result;
      },
    });
  10. Implement nested routers without constants

    As of version 3.14.0, ts-rest supports the declaration of nested routers without the need to declare new constants, simplifying the routing structure.
  11. Apply middleware to individual routes

    You can apply middleware to specific routes by passing an object containing middleware and handler to the route definition. To maintain type safety for both global and route-specific request contexts, use the tsr.routeWithMiddleware() helper.
    import { fetchRequestHandler, tsr } from '@ts-rest/serverless/fetch';
    import { contract } from './contract';
    
    type GlobalRequestContext = {
      time: Date;
    };
    
    export default async (request: Request) => {
      return fetchRequestHandler({
        request,
        contract,
        router: {
          getPost: tsr.routeWithMiddleware(contract.getPost)<
            GlobalRequestContext, // global context
            { userId: string }      // route-level context
          >({
            middleware: [
              (request) => {
                request.userId = '123';
              },
            ],
            handler: async ({ params: { id } }, { request }) => {
              const post = prisma.post.findUniqueOrThrow({
                where: { id, ownerId: request.userId },
              });
    
              return {
                status: 200,
                body: post,
              };
            },
          }),
        },
        options: {
          requestMiddleware: [
            tsr.middleware<GlobalRequestContext>((request) => {
              request.time = new Date();
            }),
          ],
        },
      });
    };
  12. Migrate paths from functions to strings (v3.0.0)

    In version 3.0.0, paths in core, express, nest, next, and open-api were migrated to be defined as strings rather than functions.