Skip to content

A set of utilities to generate an API client, types, mocks & react-query hooks for OpenAPI

License

Notifications You must be signed in to change notification settings

greeeg/openapi-kit

Repository files navigation

OpenAPI kit

npm version npm downloads bundle size

A set of utilities to generate an API client, types, mocks & react-query hooks for OpenAPI

Features

  • Parse OpenAPI 3 & OpenAPI 3.1 YML/JSON documents
  • Generate Typescript types for OpenAPI components & paths
  • Generate a typed API client with named methods for OpenAPI operations
  • Generate mock data for OpenAPI operations
  • Generate react-query query & mutation hooks for OpenAPI operations

Getting started

OpenAPI kit comes with a command you can execute to get quickly started.

If the command does not provide enough options for your generation needs, check out the "Advanced usage" section to create your own script.

yarn add -D openapi-kit

# Used by API client
yarn add query-string

# Used by `react-query` hooks
yarn add @tanstack/react-query
{
  "name": "my-app",
  "scripts": {
    "openapi": "openapi-kit generate -f ./openapi/pet-store.yml -o ./generated"
  }
}

CLI options

# Specify the OpenAPI spec file path & output directory
openapi-kit generate -f ./openapi/pet-store.yml -o ./generated

# The `prettyOutput` flag ensures the output is formatted using Prettier
openapi-kit generate -f ./openapi/pet-store.yml -o ./generated --prettyOutput

# Only generate type definitions
openapi-kit generate -f ./openapi/pet-store.yml -o ./generated --types

# Only generate type definitions & API client
openapi-kit generate -f ./openapi/pet-store.yml -o ./generated --types --apiClient

# Only generate type definitions & mock data
openapi-kit generate -f ./openapi/pet-store.yml -o ./generated --types --mockData

Using types

import { Components, Paths } from 'generated/typeDefinitions'

type Pet = Components.Schemas.Pet

const pet: Pet = {
  id: 1,
  name: 'Paul',
  tag: 'happy',
}

const getPetNames = (response: Paths.ListPets.Responses.$200): string[] => {
  return response.map((pet) => pet.name)
}

Using API client

import { getAPIClient } from 'generated/apiClient'

const apiClient = getAPIClient({
  baseUrl: 'https://petstore.swagger.io/v2',
  headers: {
    Accept: 'application/json',
  },
  onError: (error: unknown) => {
    if (error instanceof HTTPRequestError && error.statusCode === 401) {
      // Do something
    }
  },
})

const response = await apiClient.showPetById({
  pathParams: {
    petId: 1,
  },
})

if (response.ok) {
  console.log(response.data.name)
}

Using mock data

import PetsList from 'components/PetsList'
import { ListPetsResponse$200 } from 'generated/mockData'

const App = () => {
  return <PetsList data={ListPetsResponse$200} />
}

Using react-query hooks

First, update your React App to include two React context providers:

  • One for react-query
  • One for your API client
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import { APIClientProvider } from 'generated/reactQuery'

const queryClient = new QueryClient()

const App = () => {
  return (
    <APIClientProvider
      config={{
        baseUrl: 'https://petstore.swagger.io/v2',
        headers: {
          Accept: 'application/json',
        },
      }}
    >
      <QueryClientProvider client={queryClient}>
        <MyComponent />
      </QueryClientProvider>
    </APIClientProvider>
  )
}

Then, use autogenerated queries & mutations in your app pages & components.

import { useListPets } from 'generated/reactQuery'

const PetsList = () => {
  const { data, isLoading } = useListPets({
    pathParams: {
      owner: 'John',
    },
    queryParams: {},
  })

  if (isLoading || !data) {
    return <span>Loading...</span>
  }

  return (
    <ul>
      {data.map((pet) => (
        <li key={pet.id}>{pet.name}</li>
      ))}
    </ul>
  )
}

export default PetsList

Advanced usage

OpenAPI kit exports a set of functions you can use in your own scripts to export types in multiple folders or choose to not export react-query hooks for example.

import {
  dereferenceDocument,
  generateAPIClient,
  generateReactQueryHooks,
  generateTypeDefinitions,
  parseDocument,
} from 'openapi-kit'

const run = () => {
  const document = await parseDocument('./pet-store.yml')
  if (!document) {
    return
  }

  generateTypeDefinitions(document, { outputFilePath: './client/generated/types.ts' })
  generateTypeDefinitions(document, { outputFilePath: './api/generated/types.ts' })
}

run()