A fully typed API client generator powered by OpenAPI.
Fetch-compatible, auto-generated types, zero generics required.
devup-api reads your openapi.json file and automatically generates a fully typed client that behaves like an ergonomic, type-safe version of fetch().
No manual type declarations. No generics. No SDK boilerplate.
Just write API calls β the types are already there.
- Reads
openapi.jsonand transforms every path, method, schema into typed API functions. - Parameters, request bodies, headers, responses β all typed automatically.
- No need to write or maintain separate TypeScript definitions.
devup-api feels like using fetch, but with superpowers:
- Path params automatically replaced
- Query/body/header types enforced
- Typed success & error responses
- Optional runtime schema validation
- Minimal abstraction over standard fetch
- Works seamlessly with Vite, Next.js, Webpack, and Rsbuild
- Automatic type generation during build time
- Zero runtime overhead
# For Vite projects
npm install @devup-api/fetch @devup-api/vite-plugin
# For Next.js projects
npm install @devup-api/fetch @devup-api/next-plugin
# For Webpack projects
npm install @devup-api/fetch @devup-api/webpack-plugin
# For Rsbuild projects
npm install @devup-api/fetch @devup-api/rsbuild-pluginVite (vite.config.ts):
import { defineConfig } from 'vite'
import devupApi from '@devup-api/vite-plugin'
export default defineConfig({
plugins: [devupApi()],
})Next.js (next.config.ts):
import devupApi from '@devup-api/next-plugin'
export default devupApi({
reactStrictMode: true,
})Webpack (webpack.config.js):
const { devupApiWebpackPlugin } = require('@devup-api/webpack-plugin')
module.exports = {
plugins: [new devupApiWebpackPlugin()],
}Rsbuild (rsbuild.config.ts):
import { defineConfig } from '@rsbuild/core'
import { devupApiRsbuildPlugin } from '@devup-api/rsbuild-plugin'
export default defineConfig({
plugins: [devupApiRsbuildPlugin()],
})Place your openapi.json file in the project root (or specify a custom path in plugin options).
Add the generated type definitions to your tsconfig.json:
{
"compilerOptions": {
// ... your compiler options
},
"include": [
"src",
"df/**/*.d.ts"
]
}Note: The
dfdirectory is the default temporary directory where generated types are stored. If you've customizedtempDirin plugin options, adjust the path accordingly (e.g.,"your-temp-dir/**/*.d.ts").
import { createApi } from '@devup-api/fetch'
const api = createApi('https://api.example.com')
// Use operationId
const users = await api.get('getUsers', {})
// Or use the path directly
const user = await api.get('/users/{id}', {
params: { id: '123' },
headers: {
Authorization: 'Bearer TOKEN'
}
})
// POST request with typed body
const newUser = await api.post('createUser', {
body: {
name: 'John Doe',
email: 'john@example.com'
}
})devup-api uses a two-phase typing system to ensure smooth development experience:
Cold typing refers to the state before the TypeScript interface files are generated. This happens when:
- You first install the plugin
- The build hasn't run yet
- The generated
api.d.tsfile doesn't exist
During cold typing:
- All API types are treated as
any - Type checking is relaxed to prevent type errors
- Your code will compile and run without issues
- You can write API calls without waiting for type generation
// Cold typing: No type errors even if api.d.ts doesn't exist yet
const api = createApi('https://api.example.com')
const result = await api.get('getUsers', {}) // β
Works, types are 'any'Bold typing refers to the state after the TypeScript interface files are generated. This happens when:
- The build tool has run (
devorbuild) - The plugin has generated
api.d.tsin the temp directory - TypeScript can find and use the generated types
During bold typing:
- All API types are strictly enforced
- Full type safety is applied
- Type errors will be caught at compile time
- You get full IntelliSense and autocomplete
// Bold typing: Full type safety after api.d.ts is generated
const api = createApi('https://api.example.com')
const result = await api.get('getUsers', {})
// β
Fully typed: result.data is typed based on your OpenAPI schema
// β Type error if you use wrong parameters or pathsThis two-phase approach ensures:
- No blocking: You can start coding immediately without waiting for the build
- Gradual typing: Types become available as soon as the build runs
- Production safety: Full type checking in production builds
- Developer experience: No false type errors during initial setup
This is a monorepo containing multiple packages:
@devup-api/core- Core types and interfaces@devup-api/utils- Utility functions for OpenAPI processing@devup-api/generator- TypeScript interface generator from OpenAPI schemas@devup-api/fetch- Type-safe API client@devup-api/vite-plugin- Vite plugin@devup-api/next-plugin- Next.js plugin@devup-api/webpack-plugin- Webpack plugin@devup-api/rsbuild-plugin- Rsbuild plugin
// Using operationId
const users = await api.get('getUsers', {
query: { page: 1, limit: 20 }
})
// Using path
const users = await api.get('/users', {
query: { page: 1, limit: 20 }
})const newPost = await api.post('createPost', {
body: {
title: 'Hello World',
content: 'This is a typed API request.'
}
})const post = await api.get('/posts/{id}', {
params: { id: '777' }
})const result = await api.get('getUser', { params: { id: '123' } })
if (result.data) {
// Success response - fully typed!
console.log(result.data.name)
} else if (result.error) {
// Error response
console.error(result.error.message)
}All plugins accept the following options:
interface DevupApiOptions {
/**
* OpenAPI file path
* @default 'openapi.json'
*/
openapiFile?: string
/**
* Temporary directory for storing generated files
* @default 'df'
*/
tempDir?: string
/**
* Case conversion type for API endpoint names and parameters
* @default 'camel'
*/
convertCase?: 'snake' | 'camel' | 'pascal' | 'maintain'
/**
* Whether to make all properties non-nullable by default
* @default false
*/
requestDefaultNonNullable?: boolean
/**
* Whether to make all request properties non-nullable by default
* @default true
*/
responseDefaultNonNullable?: boolean
}- Plugin reads your
openapi.jsonduring build time - Extracts paths, methods, schemas, parameters, and request bodies
- Generates TypeScript interface definitions automatically
- Creates a URL map for operationId-based API calls
- Builds a typed wrapper around
fetch()with full type safety
# Install dependencies
bun install
# Build all packages
bun run build
# Run tests
bun test
# Lint
bun run lint
# Fix linting issues
bun run lint:fixThis project is inspired by openapi-fetch, a fantastic library for type-safe API clients. devup-api builds upon similar concepts while providing additional features like build-time type generation and seamless integration with modern build tools.
Apache 2.0