Documentation
OpenAPI Sync is a powerful developer tool that automates the generation of TypeScript types, API clients (Fetch, Axios, React Query, SWR, RTK Query), runtime validation schemas (Zod, Yup, Joi), and endpoint definitions from your OpenAPI specifications in real-time.
Latest Version: 5.0.0 - Major improvements to client generation with bug fixes, better TypeScript support, and enhanced developer experience!
Getting Started with OpenAPI Sync
Duration: 0:10Learn the basics of OpenAPI Sync and how it can automate your API development workflow.
Watch on YouTubeInstallation
Installation & Setup
Duration: 0:10Step-by-step guide to installing and configuring OpenAPI Sync in your project.
Watch on YouTubeInstall OpenAPI Sync using your preferred package manager:
# NPM
npm install openapi-sync
# Yarn
yarn add openapi-sync
# PNPM
pnpm add openapi-sync
# Global Installation
npm install -g openapi-sync
# Direct Usage (No Installation)
npx openapi-syncQuick Start
Quick Start Tutorial
Duration: 0:10Get up and running with OpenAPI Sync in under 5 minutes with this quick start guide.
Watch on YouTube1. Create Configuration
Create a configuration file in your project root:
// openapi.sync.json
{
"refetchInterval": 5000,
"folder": "./src/api",
"api": {
"petstore": "https://petstore3.swagger.io/api/v3/openapi.json"
}
}2. Run Sync Command
npx openapi-sync3. Use Generated Code
import { getPetById } from "./src/api/petstore/endpoints";
import { IPet } from "./src/api/petstore/types";
// Use the endpoint URL
const petUrl = getPetById("123"); // Returns: "/pet/123"
// Use the generated types
const pet: IPet = {
id: 1,
name: "Fluffy",
status: "available"
};Basic Configuration
Basic Configuration
Duration: 0:10Learn how to configure OpenAPI Sync with JSON, TypeScript, or JavaScript config files.
Watch on YouTubeOpenAPI Sync supports multiple configuration formats:
openapi.sync.json- JSON formatopenapi.sync.ts- TypeScript formatopenapi.sync.js- JavaScript format
Configuration Options
| Property | Type | Description |
|---|---|---|
| refetchInterval | number | Milliseconds between API refetches (dev only) |
| folder | string | Output directory for generated files |
| api | Record<string, string> | Map of API names to OpenAPI spec URLs |
| server | number | string | Server index or custom server URL |
Folder Splitting
Folder Splitting & Organization
Duration: 0:10Organize your generated code by tags or custom logic for better project structure.
Watch on YouTubeOrganize your generated code into folders based on tags or custom logic.
Split by Tags
folderSplit: {
byTags: true // Creates folders like admin/, user/, pet/
}Custom Folder Logic
folderSplit: {
customFolder: ({ method, path, tags, operationId }) => {
// Admin endpoints go to admin folder
if (tags?.includes("admin")) return "admin";
// API versioning
if (path.startsWith("/api/v1/")) return "v1";
if (path.startsWith("/api/v2/")) return "v2";
// Method-based organization
if (method === "GET") return "read";
if (method === "POST" || method === "PUT") return "write";
return null; // Use default structure
}
}Generated Structure
src/api/
├── petstore/
│ ├── admin/
│ │ ├── endpoints.ts
│ │ └── types.ts
│ ├── user/
│ │ ├── endpoints.ts
│ │ └── types.ts
│ └── pet/
│ ├── endpoints.ts
│ └── types.ts
└── shared.tsValidation Schemas
Runtime Validation with Zod, Yup & Joi
Duration: 0:10Generate and use runtime validation schemas for type-safe API requests.
Watch on YouTubeGenerate runtime validation schemas using Zod, Yup, or Joi from your OpenAPI specification.
Configuration
validations: {
library: "zod", // "zod" | "yup" | "joi"
generate: {
query: true, // Generate query parameter validations
dto: true // Generate request body validations
},
name: {
prefix: "I",
suffix: "Schema",
useOperationId: true
}
}Installation
# For Zod
npm install zod
# For Yup
npm install yup
# For Joi
npm install joiUsage Example
import { IAddPetDTOSchema } from "./src/api/petstore/validation";
import { z } from "zod";
// Validate request body
try {
const validatedData = IAddPetDTOSchema.parse(req.body);
// Data is now validated and typed
} catch (error) {
if (error instanceof z.ZodError) {
console.error("Validation errors:", error.errors);
}
}Express Middleware
import { Request, Response, NextFunction } from "express";
import { z } from "zod";
export const validate = <T extends z.ZodTypeAny>(schema: T) => {
return (req: Request, res: Response, next: NextFunction) => {
try {
schema.parse(req.body);
next();
} catch (error) {
if (error instanceof z.ZodError) {
res.status(400).json({
error: "Validation failed",
details: error.errors
});
}
}
};
};
// Usage
import { IAddPetDTOSchema } from "./api/validation";
router.post("/pet", validate(IAddPetDTOSchema), handler);Custom Code Preservation
Custom Code Preservation
Duration: 0:10Learn how to add custom code that survives regeneration using special markers.
Watch on YouTubeAdd your own custom code that will survive when files are regenerated.
Configuration
customCode: {
enabled: true, // Enable custom code preservation
position: "bottom", // "top" | "bottom" | "both"
markerText: "CUSTOM CODE", // Custom marker text
includeInstructions: true // Include helpful instructions
}Usage
// endpoints.ts (after generation)
export const getPet = (petId: string) => `/pet/${petId}`;
// 🔒 CUSTOM CODE START
// Add your custom code here - it will be preserved
export const legacyGetPet = (id: string) => `/api/v1/pet/${id}`;
export const buildPetUrl = (petId: string, includePhotos: boolean) => {
const base = getPet(petId);
return includePhotos ? `${base}?include=photos` : base;
};
// 🔒 CUSTOM CODE END
export const updatePet = (petId: string) => `/pet/${petId}`;Endpoint Filtering
Endpoint Filtering & Selection
Duration: 0:10Filter endpoints by tags, paths, or regex patterns to control what gets generated.
Watch on YouTubeControl which endpoints are included in code generation.
Exclude Endpoints
endpoints: {
exclude: {
// Exclude by tags
tags: ["deprecated", "internal"],
// Exclude specific endpoints
endpoints: [
{ path: "/admin/users", method: "DELETE" },
{ regex: "^/internal/.*", method: "GET" },
{ path: "/debug" } // All methods
]
}
}Include Only Specific Endpoints
endpoints: {
include: {
// Include only public endpoints
tags: ["public"],
// Include specific endpoints
endpoints: [
{ path: "/public/users", method: "GET" },
{ regex: "^/public/.*" }
]
}
}API Client Generation
Automatically generate fully-typed API clients and hooks for popular libraries directly from your OpenAPI specifications.
Generate clients for Fetch, Axios, React Query, SWR, and RTK Query with full TypeScript support!
API Client Generation Overview
Duration: 0:10Introduction to generating fully-typed API clients from your OpenAPI specification.
Watch on YouTubeSupported Client Types
- fetch - Native browser Fetch API with TypeScript types
- axios - Axios client with interceptors and error handling
- react-query - React Query/TanStack Query hooks (v4 & v5)
- swr - SWR hooks for React
- rtk-query - Redux Toolkit Query API slice
Basic Usage
# Generate Fetch client
npx openapi-sync generate-client --type fetch
# Generate Axios client
npx openapi-sync generate-client --type axios
# Generate React Query hooks
npx openapi-sync generate-client --type react-query
# Generate SWR hooks
npx openapi-sync generate-client --type swr
# Generate RTK Query API
npx openapi-sync generate-client --type rtk-queryFilter by Tags or Endpoints
Generate clients for specific endpoints only:
# Filter by tags
npx openapi-sync generate-client --type fetch --tags pets,users
# Filter by endpoint names
npx openapi-sync generate-client --type axios --endpoints getPetById,createPet
# Generate for specific API
npx openapi-sync generate-client --type react-query --api petstore
# Specify output directory
npx openapi-sync generate-client --type swr --output ./src/clients
# Set base URL
npx openapi-sync generate-client --type fetch --base-url https://api.example.comReact Query Example
Complete example using React Query hooks:
// 1. Generate the client
// npx openapi-sync generate-client --type react-query
// 2. Setup in your app
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import apiClient from "./api/petstore/client/client";
// Configure API client
apiClient.updateConfig({
baseURL: "https://api.example.com",
});
apiClient.setAuthToken("your-auth-token");
const queryClient = new QueryClient();
function App() {
return (
<QueryClientProvider client={queryClient}>
<YourComponent />
</QueryClientProvider>
);
}
// 3. Use in components
import { useGetPetById, useCreatePet } from "./api/petstore/client/hooks";
function PetDetails({ petId }: { petId: string }) {
// Query hook for GET requests
const { data, isLoading, error } = useGetPetById({ petId });
// Mutation hook for POST/PUT/PATCH/DELETE
const createPet = useCreatePet({
onSuccess: (newPet) => {
console.log("Pet created:", newPet);
},
});
const handleCreate = () => {
createPet.mutate({
data: {
name: "Fluffy",
species: "cat",
},
});
};
if (isLoading) return <div>Loading...</div>;
if (error) return <div>Error: {error.message}</div>;
return (
<div>
<h1>{data?.name}</h1>
<p>Status: {data?.status}</p>
<button onClick={handleCreate}>Create New Pet</button>
</div>
);
}Fetch Client Example
import { setApiConfig, getPetById, createPet } from "./api/petstore/client";
// Configure the client
setApiConfig({
baseURL: "https://api.example.com",
auth: { token: "your-token" },
headers: {
"X-Custom-Header": "value",
},
});
// Use the client
async function fetchPet(petId: string) {
try {
const pet = await getPetById({ petId });
console.log("Pet:", pet);
} catch (error) {
if (error instanceof ApiError) {
console.error("API Error:", error.statusCode, error.response);
}
}
}
async function addNewPet() {
const newPet = await createPet({
data: {
name: "Max",
species: "dog",
age: 3,
},
});
console.log("Created:", newPet);
}Axios Client Example
import apiClient from "./api/petstore/client";
// Configure the client
apiClient.updateConfig({
baseURL: "https://api.example.com",
timeout: 10000,
headers: {
"X-App-Version": "1.0.0",
},
});
// Set auth token
apiClient.setAuthToken("your-auth-token");
// Use the client
async function example() {
// GET request
const pet = await apiClient.getPetById({ petId: "123" });
// POST request
const newPet = await apiClient.createPet({
data: {
name: "Buddy",
species: "dog",
},
});
// PUT request
await apiClient.updatePet(
{ petId: "123" },
{ name: "Buddy Updated" }
);
// DELETE request
await apiClient.deletePet({ petId: "123" });
}SWR Hooks Example
import { useGetPetById, useCreatePet } from "./api/petstore/client/hooks";
function PetProfile({ petId }: { petId: string }) {
// SWR automatically handles caching, revalidation, and more
const { data, error, isLoading, mutate } = useGetPetById({ petId });
const { trigger, isMutating } = useCreatePet();
const handleCreate = async () => {
try {
const newPet = await trigger({
arg: {
data: {
name: "Charlie",
species: "cat",
},
},
});
// Revalidate the pet list
mutate();
} catch (err) {
console.error("Failed to create pet:", err);
}
};
if (isLoading) return <div>Loading...</div>;
if (error) return <div>Error loading pet</div>;
return (
<div>
<h2>{data?.name}</h2>
<button onClick={handleCreate} disabled={isMutating}>
{isMutating ? "Creating..." : "Create New Pet"}
</button>
</div>
);
}RTK Query Example
// 1. Setup store
import { configureStore } from "@reduxjs/toolkit";
import { apiApi } from "./api/petstore/client/api";
export const store = configureStore({
reducer: {
[apiApi.reducerPath]: apiApi.reducer,
},
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware().concat(apiApi.middleware),
});
// 2. Use in components
import { useGetPetByIdQuery, useCreatePetMutation } from "./api/petstore/client/api";
function PetCard({ petId }: { petId: string }) {
const { data, isLoading, error } = useGetPetByIdQuery({
params: { petId }
});
const [createPet, { isLoading: isCreating }] = useCreatePetMutation();
const handleCreate = async () => {
try {
await createPet({
data: {
name: "Luna",
species: "cat",
},
}).unwrap();
alert("Pet created!");
} catch (err) {
console.error("Failed:", err);
}
};
return (
<div>
{isLoading && <div>Loading...</div>}
{error && <div>Error!</div>}
{data && (
<div>
<h3>{data.name}</h3>
<p>{data.species}</p>
</div>
)}
<button onClick={handleCreate} disabled={isCreating}>
Create Pet
</button>
</div>
);
}Generated File Structure
api/
└── petstore/
├── client/
│ ├── client.ts # Base API client
│ ├── hooks.ts # React Query/SWR hooks
│ ├── api.ts # RTK Query API (if applicable)
│ ├── index.ts # Exports
│ └── README.md # Usage documentation
├── endpoints.ts
├── types/
│ ├── index.ts
│ └── shared.ts
└── validations.tsConfiguration Options
// openapi.sync.ts
import { IConfig } from "openapi-sync/types";
const config: IConfig = {
folder: "./src/api",
api: {
petstore: "https://petstore3.swagger.io/api/v3/openapi.json",
},
// Client generation configuration
clientGeneration: {
enabled: true,
type: "react-query",
baseURL: "https://api.example.com",
tags: ["pets", "users"], // Optional: filter by tags
endpoints: ["getPetById"], // Optional: specific endpoints
auth: {
type: "bearer",
in: "header",
},
errorHandling: {
generateErrorClasses: true,
},
reactQuery: {
version: 5,
mutations: true,
infiniteQueries: false,
},
},
};
export default config;Custom Code Preservation
Generated clients preserve your custom code during regeneration:
// client.ts (Generated)
// Auto-generated client code...
// ============================================================
// 🔒 CUSTOM CODE START
// Add your custom code below this line
// This section will be preserved during regeneration
// ============================================================
// Your custom helper functions
export function buildPaginatedUrl(
baseUrl: string,
page: number,
limit: number
) {
return `${baseUrl}?page=${page}&limit=${limit}`;
}
// Custom interceptors
export function setupCustomInterceptors() {
// Your custom logic
}
// 🔒 CUSTOM CODE END
// ============================================================CLI Options Reference
| Option | Description | Example |
|---|---|---|
| --type, -t | Client type to generate (required) | fetch, axios, react-query, swr, rtk-query |
| --api, -a | Specific API from config | --api petstore |
| --tags | Filter by endpoint tags | --tags pets,users |
| --endpoints, -e | Filter by endpoint names | --endpoints getPetById,createPet |
| --output, -o | Output directory | --output ./src/clients |
| --base-url, -b | Base URL for requests | --base-url https://api.example.com |
New in v5.0.0: All client generators now include comprehensive inline documentation, better ESLint compliance, and improved folder splitting support!
RTK Query Enhancements (v5.0.0)
Simplified Redux Store Setup
When using folder splitting, RTK Query now generates an apis.ts file with a helper object that makes Redux store configuration incredibly simple:
// Before v5.0.0 (Complex setup)
import { configureStore } from '@reduxjs/toolkit';
import { petsApi } from './pets/api';
import { usersApi } from './users/api';
import { ordersApi } from './orders/api';
export const store = configureStore({
reducer: {
[petsApi.reducerPath]: petsApi.reducer,
[usersApi.reducerPath]: usersApi.reducer,
[ordersApi.reducerPath]: ordersApi.reducer,
},
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware()
.concat(petsApi.middleware)
.concat(usersApi.middleware)
.concat(ordersApi.middleware),
});// After v5.0.0 (Simple setup!)
import { configureStore } from '@reduxjs/toolkit';
import { setupApiStore } from './api/petstore/apis';
export const store = configureStore({
reducer: setupApiStore.reducer,
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware().concat(setupApiStore.middleware),
});
// That's it! All API slices are automatically configured ✨Unique Reducer Paths
Each API slice now has a unique reducerPath based on its folder name, preventing conflicts:
// Generated pets/api.ts
const petsApi = createApi({
reducerPath: 'petsApi', // ✅ Unique!
// ...
});
// Generated users/api.ts
const usersApi = createApi({
reducerPath: 'usersApi', // ✅ Unique!
// ...
});
// No more "Duplicate property" TypeScript errors!Default Exports for Better Imports
API slices now export as default, making imports cleaner:
// Clean default import
import petsApi from './pets/api';
import { useGetPetsQuery } from './pets/api';
// Or use the aggregated apis.ts
import { petsApi, useGetPetsQuery } from './apis';SWR Improvements (v5.0.0)
Fixed Mutation Type Errors
SWR mutation hooks now have correct TypeScript types, fixing the double-nesting issue:
// v5.0.0 - Correct types! ✅
export function useCreatePet(
config?: SWRMutationConfiguration<
Pet,
Error,
string,
{ data: PetRequest } // Correct: single level
>
) {
return useSWRMutation(
'createPet',
async (_, { arg }: { arg: { data: PetRequest } }) => {
return apiClient.createPet(arg);
},
config
);
}
// Usage - works perfectly!
const { trigger } = useCreatePet();
await trigger({ arg: { data: { name: 'Fluffy' } } });Comprehensive Inline Documentation
Every generated SWR hooks file now includes 230+ lines of usage examples and patterns:
/**
* SWR Hooks - Complete Usage Guide
*
* ## Quick Start
*
* 1. Configure SWR globally:
* ```typescript
* <SWRConfig value={{ revalidateOnFocus: false }}>
* {children}
* </SWRConfig>
* ```
*
* ## Examples
*
* ### Reading Data (GET)
* ```typescript
* const { data, error, isLoading } = useGetPets();
* ```
*
* ### Creating Data (POST)
* ```typescript
* const { trigger, isMutating } = useCreatePet();
* await trigger({ arg: { data: { name: 'Luna' } } });
* ```
*
* ### Optimistic Updates
* ```typescript
* revalidate({ ...data, name: newName }, false);
* await trigger({ arg: { ... } });
* await revalidate(); // Sync with server
* ```
*
* [... 200+ more lines of examples ...]
*/Fetch Client Fixes (v5.0.0)
Fixed Naming Conflicts
Endpoint imports are now automatically aliased to prevent naming conflicts:
// Generated imports (aliased to avoid conflicts)
import {
getPets as getPets_endpoint,
getPetById as getPetById_endpoint,
createPet as createPet_endpoint,
} from './endpoints';
// Generated functions (no conflict!)
export async function getPets() {
const _url = getPets_endpoint; // Uses aliased import
return fetchAPI(_url, { method: 'GET' });
}
export async function getPetById(params: { url: { id: string } }) {
const _url = getPetById_endpoint(params.url.id); // Uses aliased import
return fetchAPI(_url, { method: 'GET' });
}ESLint-Compliant Default Exports
Default exports now use named variables, satisfying ESLint rules:
// v5.0.0 - ESLint compliant! ✅
const apiClient = {
setApiConfig,
getPets,
getPetById,
createPet,
};
export default apiClient;
// No more "Assign object to variable" ESLint warnings!File Organization Improvements (v5.0.0)
Non-Folder-Split Mode
When folder splitting is disabled, files are now generated directly at the root level:
api/
└── petstore/
├── clients.ts # All API client functions
├── hooks.ts # All React Query/SWR hooks
├── endpoints.ts # Endpoint definitions
├── types.ts # TypeScript types
└── validations.ts # Validation schemas
# Clean, simple structure for smaller APIs!Folder-Split Mode
With folder splitting, each tag gets its own folder with complete isolation:
api/
└── petstore/
├── clients.ts # Aggregates all clients (Fetch/Axios)
├── hooks.ts # Aggregates all hooks (React Query/SWR)
├── apis.ts # Aggregates all APIs (RTK Query) + setupApiStore
├── pets/
│ ├── client.ts # Pet-specific client
│ ├── hooks.ts # Pet-specific hooks
│ ├── api.ts # Pet-specific RTK Query API
│ ├── types.ts # Pet-specific types
│ └── endpoints.ts # Pet-specific endpoints
└── users/
├── client.ts
├── hooks.ts
├── api.ts
├── types.ts
└── endpoints.ts
# Perfect for large APIs with many endpoints!💡 Migration Tip: To get all these improvements, simply regenerate your clients:
npx openapi-sync generate-client --type [your-type]All improvements are backwards compatible - your existing code will continue to work!
CLI Usage
CLI Commands & Options
Duration: 0:10Master the OpenAPI Sync CLI with all available commands and options.
Watch on YouTube# Sync API types and endpoints
npx openapi-sync
# Generate API client
npx openapi-sync generate-client --type react-query
# Run with custom refetch interval
npx openapi-sync --refreshinterval 30000
npx openapi-sync -ri 30000
# Get help
npx openapi-sync --help
npx openapi-sync generate-client --helpCLI Improvements (v5.0.0)
CLI Arguments Override Config
CLI options now correctly override configuration file settings:
# Config file says type: "fetch"
# But CLI argument takes precedence:
npx openapi-sync generate-client --type rtk-query
# Result: Generates RTK Query (not Fetch) ✅
# This works for all options:
npx openapi-sync generate-client \
--type swr \
--base-url https://api.example.com \
--tags pets,users
# CLI values override config values!Streamlined Interactive Setup
The interactive setup wizard is now simpler - selecting folder splitting automatically enables tag-based organization:
# npx openapi-sync init
? Organize generated code into folders by OpenAPI tags? Yes
# ✅ Automatically enables byTags: true
# (No extra question needed!)
? Generate API client code? Yes
? Which client type would you like? React Query
# ... continues with setupProgrammatic Usage
Programmatic API Usage
Duration: 0:10Use OpenAPI Sync programmatically in your Node.js scripts and build tools.
Watch on YouTubeimport { Init } from "openapi-sync";
// Initialize with default config
await Init();
// Initialize with custom options
await Init({
refetchInterval: 30000
});
// With error handling
try {
await Init({
refetchInterval: process.env.NODE_ENV === "development" ? 5000 : 0
});
console.log("API types synchronized successfully");
} catch (error) {
console.error("Failed to sync API types:", error);
}Troubleshooting
Common Issues & Troubleshooting
Duration: 0:10Learn how to debug and resolve common issues when using OpenAPI Sync.
Watch on YouTubeConfiguration File Not Found
Error: No config found
Solution: Ensure you have one of these files in your project root:openapi.sync.json, openapi.sync.ts, or openapi.sync.js
Network Timeout Errors
Error: timeout of 60000ms exceeded
Solution: The tool includes automatic retry with exponential backoff. Check your internet connection and verify the OpenAPI spec URL is accessible.
TypeScript Compilation Errors
Error: Cannot find module './src/api/petstore/types'
Solution: Ensure the sync process completed successfully and check that the folder path in config is correct.
API Reference
Init(options?: InitOptions)
Initializes OpenAPI sync with the specified configuration.
import { Init } from "openapi-sync";
await Init({
refetchInterval: 10000
});Exported Types
import {
IConfig,
IOpenApiSpec,
IOpenApSchemaSpec,
IConfigReplaceWord,
IConfigExclude,
IConfigInclude,
IConfigDoc
} from "openapi-sync/types";Changelog
Track the evolution of OpenAPI Sync with detailed release notes and version history.
v5.0.0
LATESTOctober 25, 2025Major improvements to client generation with enhanced TypeScript support, better developer experience, and critical bug fixes
- 🎉 RTK Query: Simplified Redux store setup with setupApiStore helper (15 lines → 5 lines)
- ✅ RTK Query: Unique reducer paths per folder preventing TypeScript conflicts
- ✅ RTK Query: Default exports for cleaner imports
- ✅ SWR: Fixed mutation hooks type errors (no more double-nesting)
- 📚 SWR: Added 230+ lines of comprehensive inline documentation and usage examples
- ✅ Fetch: Fixed naming conflicts with aliased endpoint imports (_endpoint suffix)
- ✅ Fetch: ESLint-compliant default exports using named variables
- 🚀 CLI: Arguments now correctly override config file settings
- 🎯 CLI: Streamlined interactive setup (auto-enables byTags when folder splitting)
- 📦 Structure: Non-folder-split mode generates files directly at root (clients.ts, hooks.ts)
- 🎨 DX: Better TypeScript support across all client types
- ⚡ Performance: Optimized code generation and improved error handling
v4.1.0
2024API Client Generation - Generate fully-typed clients for Fetch, Axios, React Query, SWR, and RTK Query with custom code preservation
v4.0.0
2024Major release with validation schema generation support (Zod, Yup, Joi) for runtime type validation
v2.1.13
Type definition fixes, clean up tsup build configuration, and introduction of comprehensive unit testing
v2.1.11
Folder splitting configuration for organized code generation by tags or custom logic
v2.1.10
OperationId-based naming for types and endpoints, enhanced filtering and tag support
📖 Full Changelog: For complete release notes and detailed changes, visit the dedicated Changelog page.