API Dev β OpenAPI Specs β SDK Package β API Client Configuration β API Client UsageA project demonstrating streamlined API client SDK development workflow - from OpenAPI spec generation, to client SDK publishing, configuration, and consumption:)
This project uses a monorepo (Turborepo) for demonstration purpose.
root (turbo monorepo)
βββ apps/
β βββ products-api/ # Product API service (NestJS)
β βββ users-api/ # User API service (NestJS)
β βββ ecom-app/ # Demo web app (Next.js)
β βββ app/
β β βββ api/
β β βββ products/
β β β βββ route.ts
β β β βββ [id]/
β β β βββ route.ts
β β βββ users/
β β βββ route.ts
β β βββ [id]/
β β βββ route.ts
β βββ lib/
β βββ api-client-config/ # API client configuration
β
βββ packages/
β βββ openapi-fetch-runtime/ # Shared fetch runtime for generated SDKs
β
βββ .changeset/ # Changesets for versioning
β βββ config.json
β
βββ .github/
β βββ workflows/
β βββ version-release.yml # Version & Release NestJS APIs
β βββ push-spec.yml # Push API specs to SwaggerHub
β βββ publish-sdk.yml # Generate & Release & Publish SDK packages
β βββ release-base.yml # Shared release workflow
β
βββ package.json
βββ turbo.json # Turborepo config
NestJS + Swagger decorators automatically generate clean OpenAPI specs, which will be used later for SDK generation. The
operationIdin decorators maps directly to SDK method names.
Two NestJS services that auto-generate OpenAPI specs using Swagger decorators:
API Services Overview
apps/
βββ products-api/ # Product service (port: 3001)
β βββ endpoints:
β POST /products β createProduct
β GET /products β getAllProducts
β GET /products?category= β getProductsByCategory
β GET /products/:id β getProduct
βββ users-api/ # User service (port: 3002)
βββ endpoints:
POST /users β createUser
GET /users β getAllUsers
GET /users/:id β getUserTest Endpoints
# 1. Start the Service
cd apps/products-api # or cd apps/users-api
npm run dev # products: 3001, users: 3002
# 2. View API Documentation
# Products API: http://localhost:3001/api-docs
# Users API: http://localhost:3002/api-docs
# 3. Run Test Script with Sample Data
npm run demo # Executes try-{service}-api.sh
# products-api β try-products-api.sh
# users-api β try-users-api.shWhile this demo uses a centralized workflow for simplicity, each API could have its own independent versioning and publishing process in a microservices setup.
First, APIs are versioned and released with Changesets:
Version & Release NestJS APIs
.github/workflows/
βββ version-release.yml # Version & Release NestJS APIs
βββ release-base.yml # Shared release workflowThen, OpenAPI specs are generated and pushed to SwaggerHub:
.github/workflows/
βββ push-spec.yml # Version & Publish OpenAPI SpecsOnce published, API specs are available on SwaggerHub:
- π @api-client-sdk-streamline-sample | Products API
- π @api-client-sdk-streamline-sample | Users API
Instead of keeping generated SDKs in the repo, we generate and publish them directly to NPM.
Based on these OpenAPI specifications, TypeScript SDKs are automatically generated (with @openapitools/openapi-generator-cli) and published as NPM packages:
.github/workflows/
βββ publish-sdk.yml # Generate & Release & Publish SDK packages
packages/
βββ openapi-fetch-runtime/ # Shared fetch runtime for generated SDKsOnce published, SDK packages are available on NPM:
- π§³ @api-client-sdk-streamline-sample/products-api-client
- π§³ @api-client-sdk-streamline-sample/users-api-client
SDK Generation Process: A Summary
1. Pull OpenAPI specs from SwaggerHub
2. Generate TypeScript clients using `openapi-generator-cli`
3. Configure shared runtime package to avoid duplication
4. Update package metadata and documentation
5. Create GitHub release
6. Publish to NPMNow that we have our SDKs published on NPM, let's set up API client configuration in our Next.js app:
apps/ecom-app/
βββ app/
β βββ api/ # API Routes
βββ lib/
βββ api-client-config/ # API client configurationAPI Client Configuration Structure:
api-client-config/
βββ configs/ # Environment-based configuration
βββ middlewares/ # Request & Response & onError middlewares
βββ errors/ # Error handling & types
βββ api-client-cache.ts # Client instance caching
βββ api-client-config.ts # API configuration builder
βββ api-client-factory.ts # Factory pattern for client creation
βββ logger.ts # Logging utilitiesAPI Routes Structure
apps/ecom-app/
βββ app/
β βββ api/
β βββ products/
β β βββ route.ts
β β βββ [id]/
β β βββ route.ts
β βββ users/
β βββ route.ts
β βββ [id]/
β βββ route.ts
βββ lib/
βββ api-client-config/
import { getProductsApi } from '@/lib/api-client-config/api-client-factory'
export async function GET() {
try {
const productsApi = getProductsApi()
const products = await productsApi.getAllProducts()
return NextResponse.json(products)
} catch (error) {
return handleApiError(error)
}
}Test the complete workflow:
1. Start API Services and Run the Next.js App
# Using Turbo:
npm run devThis starts:
- Next.js app on
http://localhost:3000 - Products API on
http://localhost:3001 - Users API on
http://localhost:3002
Or start services individually:
# Start Products API
cd apps/products-api
npm run dev
# Start Users API
cd apps/users-api
npm run dev
# Start Next.js App
cd apps/ecom-app
npm run dev2. Test Endpoints
# Create a product
curl -X POST http://localhost:3000/api/products \
-H "Content-Type: application/json" \
-d '{
"name": "Mechanical Keyboard",
"price": 159.99,
"description": "Premium mechanical keyboard with RGB lighting",
"categories": ["electronics", "accessories"]
}'
# Get all products
curl http://localhost:3000/api/products
# Get products by category
curl 'http://localhost:3000/api/products?category=electronics'
# Get a specific product
curl http://localhost:3000/api/products/1# Create a user
curl -X POST http://localhost:3000/api/users \
-H "Content-Type: application/json" \
-d '{
"name": "Jane Smith",
"email": "jane@example.com",
"phone": "111-111-1111"
}'
# Get all users
curl http://localhost:3000/api/users
# Get a specific user
curl http://localhost:3000/api/users/1πͺ How It Works: A Short Review
1. Request hits the Next.js API routes
2. Routes instantiate configured SDK clients
3. SDK clients make HTTP requests to NestJS services
4. NestJS services process and return the response
5. SDK clients transform the responses
6. Next.js routes return the final JSON response
OpenAPI Specs on SwaggerHub:
- π @api-client-sdk-streamline-sample | Products API
- π @api-client-sdk-streamline-sample | Users API
API Client SDK Packages on NPM:



