- Output directory for generated files - -h, --help - Show help message
$3 #### Using Flag Arguments
`bashFrom 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/api`#### Using Positional Arguments
`bashFrom a URL elysia-codegen https://api.example.com/openapi.json ./src/api
From a local file elysia-codegen ./openapi.json ./generated`#### With Bun
`bashRun 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/api`
Generated Code Usage The generator creates a single
generated.ts file containing all types and hooks.
$3 All request/response types are automatically generated:
`typescript import type { User, CreateUserBody, GetUsersResponse } from './generated';// Use types in your components const user: User = { id: 1, name: 'John Doe', email: 'john@example.com' };
`
$3 #### Query Hooks (GET requests)
`typescript import { useGetUsers, useGetUserById } from './api/generated';function UsersList() { // Simple query with no parameters const { data, isLoading, error } = useGetUsers();
if (isLoading) return
Loading...
; if (error) return Error: {error.message}
; return (
{data?.users.map(user => ( {user.name} ))} ); }function UserProfile({ userId }: { userId: number }) { // Query with parameters const { data: user } = useGetUserById( { id: userId }, { enabled: !!userId, // React Query options staleTime: 5000, } );
return
{user?.name}
; }`#### Mutation Hooks (POST, PUT, PATCH, DELETE)
`typescript 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) => { e.preventDefault(); const formData = new FormData(e.currentTarget);
mutate({ name: formData.get('name') as string, email: formData.get('email') as string, }); };
return (
); }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 (
updateUser({ id: userId, name: 'Updated Name' })}> Update deleteUser({ id: userId })}> Delete
); }`
$3 #### Custom Query Keys
`typescript 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
{/ Render users /}
; }`#### Error Handling
`typescript 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 (
{isError &&
{error.message}
}
{/
Form fields /}
); }`#### Optimistic Updates
`typescript 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
{/ Editor UI /}
; }`
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.json`
Development
$3
`bashInstall dependencies bun install`
$3
`bashRun directly with Bun during development bun index.ts -i ./example/openapi.json -o ./output`
$3
`bashCompile TypeScript to JavaScript npm run build
Test the compiled version node dist/index.js --help`The build outputs JavaScript files to the
dist/ folder, which is what gets published to npm.
How It Works 1. Fetches OpenAPI Spec : Reads from a URL or local file 2. Generates TypeScript Types : Creates interfaces from schema definitions 3. Creates React Query Hooks : Generates typed hooks for each endpoint - GET requests →
useQuery hooks - POST/PUT/PATCH/DELETE → useMutation hooks 4. Outputs Single File : All types and hooks in one generated.ts file
Limitations - Only supports
application/json` content 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