Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Orval Guide
What is Orval?
Orval is a code generator that automatically creates TypeScript types and API client code from OpenAPI/Swagger specifications. It eliminates the need to manually write API client code and ensures type safety between your backend API and frontend code.
What Orval Does
Where Does Orval Get Types From?
Orval reads types from OpenAPI/Swagger specifications. In our project:
Source Options:
Local OpenAPI JSON file (current setup):
Remote OpenAPI endpoint:
Environment variable:
How OpenAPI Specs Are Created
In our backend (
apps/indexer):@hono/zod-openapiautomatically generates OpenAPI specsDaoResponseSchema)/docsendpoint serves the OpenAPI JSON specificationapps/indexer/src/api/controllers/dao/index.tsdefines the/daoendpointHow to Generate Types
Step 1: Run Codegen Command
Step 2: Generated Files Location
After running codegen, Orval generates:
Step 3: When to Regenerate
Run
pnpm codegenwhenever:Note: Generated files are marked with
// Generated by orval- do not edit manually.What Exactly Does Orval Generate?
1. TypeScript Types
File:
shared/api/generated/schemas/dao200.ts2. API Client Functions
File:
shared/api/generated/governance/governance.tsPlain Function (for non-React usage):
React Query Hook:
3. Query Keys and Options
Configuration
Current Setup (
orval.config.ts)Available Client Types
Orval can generate different client types:
"react-query"- React Query hooks (current)"swr"- SWR hooks"axios"- Axios instances"fetch"- Fetch-based clients"svelte-query"- Svelte Query hooksPros
✅ Type Safety
✅ Automatic Code Generation
✅ Multiple Client Support
✅ OpenAPI Standard
✅ Customizable
Cons
❌ Requires OpenAPI Spec
❌ Generated Code
❌ Build Step Required
pnpm codegenafter API changes❌ Learning Curve
Limitations
🚫 GraphQL Support
Can Orval be used with GraphQL?
No, Orval does NOT support GraphQL directly.
Other Limitations
Usage Example
Before Orval (Manual):
After Orval (Type-Safe):
Project-Specific Notes
Current Setup
@hono/zod-openapigenerates OpenAPI specsshared/api/mutator.tshandles:anticapture-dao-id)File Structure
Environment Variables
INDEXER_OPENAPI_URL- Override OpenAPI spec source URLNEXT_PUBLIC_INDEXER_URL- Override API base URL in mutatorAdvanced Topics
Pagination
Orval handles pagination based on how your OpenAPI spec defines it. There are several pagination patterns:
1. Offset-Based Pagination (skip/limit)
OpenAPI Spec Example:
{ "parameters": [ { "name": "skip", "in": "query", "schema": { "type": "integer", "default": 0 } }, { "name": "limit", "in": "query", "schema": { "type": "integer", "default": 20 } } ], "responses": { "200": { "schema": { "type": "object", "properties": { "items": { "type": "array" }, "totalCount": { "type": "integer" } } } } } }Generated Hook:
2. Cursor-Based Pagination (after/before)
OpenAPI Spec Example:
{ "parameters": [ { "name": "after", "in": "query", "schema": { "type": "string" } }, { "name": "before", "in": "query", "schema": { "type": "string" } }, { "name": "limit", "in": "query", "schema": { "type": "integer", "default": 365 } } ] }Generated Hook:
3. Infinite Queries (React Query)
To enable infinite queries for cursor-based pagination, configure Orval:
Generated Infinite Hook:
Note: Currently configured with
useInfinite: false- enable if needed for infinite scroll patterns.Type System
Orval generates comprehensive TypeScript types from your OpenAPI schemas:
1. Basic Types
OpenAPI Schema:
{ "Dao200": { "type": "object", "properties": { "id": { "type": "string" }, "chainId": { "type": "number" }, "quorum": { "type": "string" } }, "required": ["id", "chainId", "quorum"] } }Generated Type:
2. Nested Types
OpenAPI Schema:
{ "ProposalResponse": { "type": "object", "properties": { "id": { "type": "string" }, "voters": { "type": "array", "items": { "$ref": "#/components/schemas/Voter" } } } }, "Voter": { "type": "object", "properties": { "address": { "type": "string" }, "weight": { "type": "string" } } } }Generated Types:
3. Union Types
OpenAPI Schema:
{ "status": { "oneOf": [ { "type": "string", "enum": ["active", "pending"] }, { "type": "null" } ] } }Generated Type:
4. Request/Response Types
Orval generates separate types for:
5. Type Inference
React Query hooks infer types automatically:
Multiple Queries
1. Multiple Endpoints
Orval generates separate hooks for each endpoint:
2. Parallel Queries
Use React Query's parallel query pattern:
3. Dependent Queries
Chain queries that depend on each other:
4. Query Batching
React Query automatically batches queries with the same key:
5. Multiple OpenAPI Specs
You can configure multiple specs in
orval.config.ts:6. Conditional Queries
Use React Query's
enabledoption:7. Query Invalidation
Invalidate and refetch queries:
Best Practices
.gitignorepnpm codegenin CI to catch type mismatchesanyenabled,staleTime, andgcTimeto optimize fetchingRelated Tools
Resources