elysia-openapi-codegen
v0.1.4
Published
Generate React Query hooks and fully typed TypeScript interfaces from Elysia OpenAPI specs.
Maintainers
Readme
Elysia OpenAPI Code Generator
Generate fully-typed React Query hooks and TypeScript interfaces from OpenAPI specifications. Perfect for Elysia.js APIs and any OpenAPI 3.x compliant backend.
Features
- Type-Safe Hooks: Automatically generates React Query hooks with full TypeScript support
- OpenAPI 3.x Compatible: Works with any valid OpenAPI specification
- Multiple Input Sources: Fetch specs from URLs or local files
- Zero Configuration: Simple CLI with sensible defaults
- React Query Integration: Generates
useQueryanduseMutationhooks ready to use - Flexible Arguments: Supports both flag-based and positional arguments
Installation
Using Bun (Recommended)
bun add -d elysia-openapi-codegenUsing npm
npm install --save-dev elysia-openapi-codegenUsing yarn
yarn add -D elysia-openapi-codegenGlobal Installation
# Bun
bun add -g elysia-openapi-codegen
# npm
npm install -g elysia-openapi-codegenUsage
CLI Flags
elysia-codegen -i <source> -o <output>Arguments:
-i, --input <source>- OpenAPI spec source (URL or file path)-o, --output <output>- Output directory for generated files-h, --help- Show help message
Examples
Using Flag Arguments
# From a URL
elysia-codegen -i https://api.example.com/openapi.json -o ./src/api
# From a local file
elysia-codegen -i ./openapi.json -o ./generated
# Using long-form flags
elysia-codegen --input https://api.example.com/openapi.json --output ./src/apiUsing Positional Arguments
# From a URL
elysia-codegen https://api.example.com/openapi.json ./src/api
# From a local file
elysia-codegen ./openapi.json ./generatedWith Bun
# Run directly with bun
bun index.ts -i https://api.example.com/openapi.json -o ./src/api
# Or using positional arguments
bun index.ts https://api.example.com/openapi.json ./src/apiGenerated Code Usage
The generator creates a single generated.ts file containing all types and hooks.
TypeScript Types
All request/response types are automatically generated:
import type { User, CreateUserBody, GetUsersResponse } from './generated';
// Use types in your components
const user: User = {
id: 1,
name: 'John Doe',
email: '[email protected]'
};React Query Hooks
Query Hooks (GET requests)
import { useGetUsers, useGetUserById } from './api/generated';
function UsersList() {
// Simple query with no parameters
const { data, isLoading, error } = useGetUsers();
if (isLoading) return <div>Loading...</div>;
if (error) return <div>Error: {error.message}</div>;
return (
<ul>
{data?.users.map(user => (
<li key={user.id}>{user.name}</li>
))}
</ul>
);
}
function UserProfile({ userId }: { userId: number }) {
// Query with parameters
const { data: user } = useGetUserById(
{ id: userId },
{
enabled: !!userId, // React Query options
staleTime: 5000,
}
);
return <div>{user?.name}</div>;
}Mutation Hooks (POST, PUT, PATCH, DELETE)
import { useCreateUser, useUpdateUser, useDeleteUser } from './api/generated';
import { useQueryClient } from '@tanstack/react-query';
function CreateUserForm() {
const queryClient = useQueryClient();
const { mutate, isPending } = useCreateUser({
onSuccess: () => {
// Invalidate and refetch
queryClient.invalidateQueries({ queryKey: ['getUsers'] });
},
});
const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
const formData = new FormData(e.currentTarget);
mutate({
name: formData.get('name') as string,
email: formData.get('email') as string,
});
};
return (
<form onSubmit={handleSubmit}>
<input name="name" required />
<input name="email" type="email" required />
<button type="submit" disabled={isPending}>
{isPending ? 'Creating...' : 'Create User'}
</button>
</form>
);
}
function UserActions({ userId }: { userId: number }) {
const queryClient = useQueryClient();
const { mutate: updateUser } = useUpdateUser({
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['getUserById', { id: userId }] });
},
});
const { mutate: deleteUser } = useDeleteUser({
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['getUsers'] });
},
});
return (
<div>
<button onClick={() => updateUser({ id: userId, name: 'Updated Name' })}>
Update
</button>
<button onClick={() => deleteUser({ id: userId })}>
Delete
</button>
</div>
);
}Advanced Usage
Custom Query Keys
import { useGetUsers } from './api/generated';
function FilteredUsers({ status }: { status: string }) {
const { data } = useGetUsers(
{ status },
{
queryKey: ['users', status], // Custom query key
staleTime: 60000,
refetchOnWindowFocus: false,
}
);
return <div>{/* Render users */}</div>;
}Error Handling
import { useCreateUser } from './api/generated';
function CreateUserForm() {
const { mutate, error, isError } = useCreateUser({
onError: (error) => {
console.error('Failed to create user:', error);
// Show toast notification, etc.
},
});
return (
<div>
{isError && <div className="error">{error.message}</div>}
{/* Form fields */}
</div>
);
}Optimistic Updates
import { useUpdateUser } from './api/generated';
import { useQueryClient } from '@tanstack/react-query';
function UserEditor({ userId }: { userId: number }) {
const queryClient = useQueryClient();
const { mutate } = useUpdateUser({
onMutate: async (newUser) => {
// Cancel outgoing refetches
await queryClient.cancelQueries({ queryKey: ['getUserById', { id: userId }] });
// Snapshot the previous value
const previousUser = queryClient.getQueryData(['getUserById', { id: userId }]);
// Optimistically update
queryClient.setQueryData(['getUserById', { id: userId }], newUser);
return { previousUser };
},
onError: (err, newUser, context) => {
// Rollback on error
queryClient.setQueryData(
['getUserById', { id: userId }],
context?.previousUser
);
},
onSettled: () => {
queryClient.invalidateQueries({ queryKey: ['getUserById', { id: userId }] });
},
});
return <div>{/* Editor UI */}</div>;
}Requirements
- TypeScript: ^5.0.0
- @tanstack/react-query: ^5.0.0 (peer dependency for generated code)
- React: ^18.0.0 (peer dependency for generated code)
Project Structure
your-project/
├── src/
│ ├── api/
│ │ └── generated.ts # Generated by this tool
│ ├── components/
│ │ └── Users.tsx # Your components using the hooks
│ └── App.tsx
├── openapi.json # Your OpenAPI spec
└── package.jsonDevelopment
Setup
# Install dependencies
bun installLocal Development
# Run directly with Bun during development
bun index.ts -i ./example/openapi.json -o ./outputBuilding for Production
# Compile TypeScript to JavaScript
npm run build
# Test the compiled version
node dist/index.js --helpThe build outputs JavaScript files to the dist/ folder, which is what gets published to npm.
How It Works
- Fetches OpenAPI Spec: Reads from a URL or local file
- Generates TypeScript Types: Creates interfaces from schema definitions
- Creates React Query Hooks: Generates typed hooks for each endpoint
- GET requests →
useQueryhooks - POST/PUT/PATCH/DELETE →
useMutationhooks
- GET requests →
- Outputs Single File: All types and hooks in one
generated.tsfile
Limitations
- Only supports
application/jsoncontent types - Uses the first server URL as the base URL
- Assumes standard REST conventions for operations
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
License
MIT
Related Projects
- Elysia - Fast and friendly Bun web framework
- TanStack Query - Powerful data synchronization for React
- OpenAPI - API specification standard
