Typesafe frontend

Generate typesafe API clients from your AdonisJS OpenAPI schema using openapi-fetch or Hey API for end-to-end type safety.

One of the main benefits of having an OpenAPI specification is the ability to generate typesafe clients for your frontend. This ensures that your frontend code stays in sync with your API without maintaining types manually.

This guide covers two popular approaches: openapi-fetch for a lightweight fetch wrapper, and Hey API for full SDK generation.

openapi-fetch

openapi-fetch is a lightweight (~6 KB) typesafe fetch client that uses your OpenAPI schema types at compile time. It does not generate any runtime code — it only needs the generated TypeScript types.

Installation

npm i openapi-fetch
npm i -D openapi-typescript

Generate types

Use openapi-typescript to generate types from your running AdonisJS server or exported schema:

npx openapi-typescript http://localhost:3333/api.json -o src/lib/api.d.ts
npx openapi-typescript ./api.json -o src/lib/api.d.ts

Add this command to your package.json scripts so you can regenerate types whenever your API changes.

package.json
{
  "scripts": {
    "generate:api": "openapi-typescript http://localhost:3333/api.json -o src/lib/api.d.ts"
  }
}

Create a client

src/lib/api.ts
import createClient from 'openapi-fetch'
import type { paths } from './api'

export const api = createClient<paths>({
  baseUrl: 'http://localhost:3333',
})

Usage

The client provides methods matching HTTP verbs. Parameters, request bodies, and responses are fully typed based on your OpenAPI schema.

// GET /posts
const { data, error } = await api.GET('/posts')

// GET /posts/:id
const { data, error } = await api.GET('/posts/{id}', {
  params: {
    path: { id: 1 },
  },
})

// POST /posts
const { data, error } = await api.POST('/posts', {
  body: {
    title: 'My new post',
    content: 'Hello world',
  },
})

Any typo in the URL path or missing required parameter will result in a TypeScript error.

Hey API

Hey API generates a full SDK from your OpenAPI specification, including typed functions for each endpoint and all request/response types.

Installation

npm i -D @hey-api/openapi-ts @hey-api/client-fetch

Configuration

Create a configuration file at the root of your frontend project:

openapi-ts.config.ts
import { defineConfig } from '@hey-api/openapi-ts'

export default defineConfig({
  input: 'http://localhost:3333/api.json',
  output: 'src/lib/api',
  plugins: ['@hey-api/client-fetch', '@hey-api/typescript', '@hey-api/sdk'],
})

Add a script to your package.json:

package.json
{
  "scripts": {
    "generate:api": "openapi-ts"
  }
}

Generate the client

npm run generate:api

This generates a complete SDK in src/lib/api/ with typed functions for each endpoint.

Usage

import { client } from './lib/api/client.gen'
import { getPosts, createPost } from './lib/api/sdk.gen'

// Configure the base URL
client.setConfig({
  baseUrl: 'http://localhost:3333',
})

// GET /posts
const { data, error } = await getPosts()

// POST /posts
const { data, error } = await createPost({
  body: {
    title: 'My new post',
    content: 'Hello world',
  },
})

Which one to choose?

openapi-fetchHey API
ApproachType-only, no code generationFull SDK generation
Bundle size~6 KBDepends on generated output
Runtime codeMinimalGenerated per endpoint
URL autocompletionPath strings with autocompletionNamed functions per endpoint
Best forLightweight projects, minimal setupLarger projects, richer DX

Both approaches give you full type safety. Choose openapi-fetch if you prefer a minimal footprint with path-based calls, or Hey API if you prefer generated functions with named methods for each endpoint.

On this page