Documentation

Add API Endpoint

Step-by-step guide for adding a new API endpoint using OpenAPI-first development.

Complete walkthrough for adding a new API endpoint with full type safety.

Overview

Adding an endpoint follows the OpenAPI-first pattern:

  1. Update OpenAPI spec
  2. Generate TypeScript clients
  3. Implement server route
  4. Use generated typed clients

Step 1: Update OpenAPI Specification

Add the endpoint to your OpenAPI spec in apps/api/openapi/openapi.json:

{
  "paths": {
    "/users/{id}": {
      "get": {
        "operationId": "getUser",
        "summary": "Get user by id",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": { "type": "string" }
          }
        ],
        "responses": {
          "200": {
            "description": "User found",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "id": { "type": "string" },
                    "email": { "type": "string" },
                    "name": { "type": "string" }
                  },
                  "required": ["id", "email", "name"]
                }
              }
            }
          },
          "404": {
            "description": "User not found",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "code": { "type": "string" },
                    "message": { "type": "string" }
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}

Step 2: Generate TypeScript Clients

Run hey-api to generate TypeScript clients:

# Generate clients for core and react packages
pnpm --filter @basilic/core gen
pnpm --filter @basilic/react gen

This generates type-safe client code in:

  • packages/core/src/gen/ - Runtime-agnostic client
  • packages/react/src/gen/ - React Query hooks

Step 3: Implement Server Route

Implement the route in apps/api/src/routes/:

// apps/api/src/routes/users.ts
import type { FastifyPluginAsync } from 'fastify'

const users: FastifyPluginAsync = async (fastify) => {
  fastify.get<{
    Params: { id: string }
  }>('/users/:id', async (request, reply) => {
    const { id } = request.params
    
    // Your implementation here
    const user = await getUserById(id)
    
    if (!user) {
      return reply.status(404).send({
        code: 'NOT_FOUND',
        message: 'User not found',
      })
    }
    
    return reply.send(user)
  })
}

export default users

Step 4: Use Generated Typed Client

The generated client is fully typed:

// In your frontend or other client
import { createApi } from '@basilic/core'
import { useUser } from '@basilic/react' // Generated React Query hook

// Runtime-agnostic client
const api = createApi({
  baseUrl: process.env.NEXT_PUBLIC_API_URL!,
  getAuthToken: async () => session?.token,
})

// Fully typed API call
const user = await api.getUser({ id: '123' })
// user is typed from OpenAPI spec

// Or use generated React Query hooks
const { data } = useUser({ id: '123' })
// data is typed as UserDTO | undefined

Checklist

  • OpenAPI spec updated in apps/api/openapi/openapi.json
  • Clients regenerated with hey-api
  • Server route implemented
  • Route matches OpenAPI spec
  • Client usage tested

On this page