skillby sgcarstrends
api-version
Manage API versioning strategy for Hono routes in apps/api/src/v1. Use when creating new API versions or migrating endpoints between versions.
Installs: 0
Used in: 1 repos
Updated: 8h ago
$
npx ai-builder add skill sgcarstrends/api-versionInstalls to .claude/skills/api-version/
# API Versioning Skill
This skill helps you manage API versions in `apps/api/src/v1/` and prepare for future versions.
## When to Use This Skill
- Creating a new API version (v2, v3, etc.)
- Deprecating old API endpoints
- Migrating endpoints between versions
- Planning breaking changes
- Maintaining backward compatibility
## Current API Structure
```
apps/api/src/
├── v1/ # Current API version
│ ├── routes/
│ │ ├── cars.ts # Car registration endpoints
│ │ ├── coe.ts # COE bidding endpoints
│ │ ├── pqp.ts # PQP data endpoints
│ │ └── health.ts # Health check
│ └── index.ts # v1 router assembly
└── index.ts # Main Hono app with versioned routes
```
## Versioning Strategy
### URL-Based Versioning
The project uses URL path versioning:
- `https://api.sgcarstrends.com/v1/cars`
- `https://api.sgcarstrends.com/v1/coe`
- Future: `https://api.sgcarstrends.com/v2/cars`
### Benefits
- Clear, explicit versioning visible in URLs
- Easy to cache and monitor per version
- Clients can migrate at their own pace
- Multiple versions can coexist
## Creating a New API Version
### Step 1: Create Version Directory
```bash
mkdir -p apps/api/src/v2/routes
```
### Step 2: Copy Existing Routes
Start with current v1 routes as a base:
```bash
cp -r apps/api/src/v1/routes/* apps/api/src/v2/routes/
```
### Step 3: Create Version Router
Create `apps/api/src/v2/index.ts`:
```typescript
import { Hono } from "hono";
import { carsRouter } from "./routes/cars";
import { coeRouter } from "./routes/coe";
import { pqpRouter } from "./routes/pqp";
const v2 = new Hono();
// Mount routes
v2.route("/cars", carsRouter);
v2.route("/coe", coeRouter);
v2.route("/pqp", pqpRouter);
export default v2;
```
### Step 4: Mount in Main App
Update `apps/api/src/index.ts`:
```typescript
import { Hono } from "hono";
import v1 from "./v1";
import v2 from "./v2";
const app = new Hono();
// Mount API versions
app.route("/v1", v1);
app.route("/v2", v2); // Add new version
// Default to latest stable version
app.route("/", v1); // Keep v1 as default or change to v2 when stable
export default app;
```
### Step 5: Implement Breaking Changes
Make necessary changes in v2 routes:
```typescript
// v1 response format
{
"success": true,
"data": [...],
"count": 10
}
// v2 response format (breaking change)
{
"data": [...],
"meta": {
"total": 10,
"page": 1,
"pageSize": 10
}
}
```
## Migration Patterns
### 1. Gradual Migration
Keep both versions running:
```typescript
// v1/routes/cars.ts - deprecated but maintained
export const carsRouter = new Hono();
carsRouter.get("/", async (c) => {
// Old logic
return c.json({
success: true,
data: await getCars(),
});
});
// v2/routes/cars.ts - new implementation
export const carsRouter = new Hono();
carsRouter.get("/", async (c) => {
// New logic with pagination
const { page = 1, limit = 10 } = c.req.query();
const result = await getCars({ page, limit });
return c.json({
data: result.items,
meta: {
total: result.total,
page,
pageSize: limit,
},
});
});
```
### 2. Feature Flag Pattern
Use feature flags to test changes:
```typescript
import { Hono } from "hono";
export const carsRouter = new Hono();
carsRouter.get("/", async (c) => {
const useV2Format = c.req.header("X-API-Version") === "2";
const data = await getCars();
if (useV2Format) {
return c.json({ data, meta: { ... } });
}
// v1 format
return c.json({ success: true, data });
});
```
### 3. Deprecation Warnings
Add deprecation headers to v1:
```typescript
import { Hono } from "hono";
export const carsRouter = new Hono();
// Add deprecation middleware
carsRouter.use("*", async (c, next) => {
await next();
c.header("X-API-Deprecation", "true");
c.header("X-API-Sunset", "2025-12-31");
c.header("Link", '<https://api.sgcarstrends.com/v2/cars>; rel="successor-version"');
});
carsRouter.get("/", async (c) => {
// Existing logic
});
```
## Breaking Changes Checklist
When introducing breaking changes, consider:
- [ ] Response structure changes
- [ ] Required parameter additions
- [ ] Authentication method changes
- [ ] URL structure modifications
- [ ] HTTP method changes
- [ ] Header requirement changes
- [ ] Error format modifications
- [ ] Data type changes
## Version Documentation
Document versions in OpenAPI/Swagger:
```typescript
// apps/api/src/v2/openapi.ts
import { OpenAPIHono } from "@hono/zod-openapi";
const app = new OpenAPIHono();
app.openapi(
{
method: "get",
path: "/cars",
summary: "Get car registrations (v2)",
deprecated: false,
tags: ["Cars"],
responses: {
200: {
description: "Success",
content: {
"application/json": {
schema: carResponseSchema,
},
},
},
},
},
async (c) => {
// Handler
}
);
```
## Version Sunset Process
### 1. Announce Deprecation
- Update documentation
- Add deprecation headers
- Notify API consumers
- Set sunset date
### 2. Monitor Usage
Track v1 usage metrics:
```typescript
import { middleware } from "hono/middleware";
v1.use("*", async (c, next) => {
// Log usage for monitoring
console.log("v1 API usage:", {
path: c.req.path,
user: c.get("user")?.id,
timestamp: new Date(),
});
await next();
});
```
### 3. Provide Migration Guide
Create migration documentation:
```markdown
# Migrating from v1 to v2
## Breaking Changes
### Response Format
**v1:**
\`\`\`json
{ "success": true, "data": [...] }
\`\`\`
**v2:**
\`\`\`json
{ "data": [...], "meta": { ... } }
\`\`\`
### Pagination
v2 includes built-in pagination:
- Query params: `?page=1&limit=10`
- Response includes `meta` with pagination info
## Migration Steps
1. Update base URL from `/v1` to `/v2`
2. Update response parsing to handle new format
3. Add pagination parameters if needed
4. Update error handling for new error format
```
### 4. Remove Old Version
After sunset date:
```bash
# Remove v1 directory
rm -rf apps/api/src/v1
# Update main app
# Remove v1 mounting from apps/api/src/index.ts
```
## Testing Multiple Versions
Test all active versions:
```bash
# Test v1
curl https://api.sgcarstrends.com/v1/cars
# Test v2
curl https://api.sgcarstrends.com/v2/cars
# Run version-specific tests
pnpm -F @sgcarstrends/api test -- src/v1
pnpm -F @sgcarstrends/api test -- src/v2
```
## Deployment Considerations
### Zero-Downtime Deployment
1. Deploy v2 alongside v1
2. Test v2 in production
3. Gradually route traffic to v2
4. Monitor error rates
5. Rollback if issues occur
### Environment Variables
Version-specific config:
```env
# v1 settings
V1_RATE_LIMIT=100
V1_CACHE_TTL=300
# v2 settings
V2_RATE_LIMIT=200
V2_CACHE_TTL=600
```
## Common Scenarios
### Scenario 1: Add Required Parameter
**v1:** Optional parameter
```typescript
carsRouter.get("/", async (c) => {
const make = c.req.query("make"); // optional
return c.json(await getCars({ make }));
});
```
**v2:** Required parameter (breaking change)
```typescript
carsRouter.get("/", async (c) => {
const make = c.req.query("make");
if (!make) {
return c.json({ error: "make parameter required" }, 400);
}
return c.json(await getCars({ make }));
});
```
### Scenario 2: Change Data Format
**v1:** Flat structure
```typescript
{ id: 1, make: "Toyota", model: "Camry" }
```
**v2:** Nested structure (breaking change)
```typescript
{
id: 1,
vehicle: {
make: "Toyota",
model: "Camry"
}
}
```
### Scenario 3: Rename Endpoint
**v1:** `/cars/list`
**v2:** `/cars` (breaking change - URL structure)
Solution: Redirect in v1
```typescript
v1.get("/cars/list", async (c) => {
c.header("X-API-Deprecated", "true");
c.header("Location", "/v2/cars");
return c.redirect("/v2/cars", 301);
});
```
## References
- Hono documentation: Use Context7 for latest docs
- Related files:
- `apps/api/src/v1/` - Current API version
- `apps/api/src/index.ts` - Main app with version mounting
- `apps/api/CLAUDE.md` - API service documentation
## Best Practices
1. **Semantic Versioning**: Use v1, v2, v3 (not v1.1, v1.2)
2. **Backward Compatibility**: Maintain old versions during migration period
3. **Documentation**: Document all breaking changes clearly
4. **Communication**: Announce deprecations well in advance
5. **Monitoring**: Track usage of deprecated endpoints
6. **Testing**: Maintain tests for all active versions
7. **Graceful Sunset**: Provide sufficient migration time (6-12 months)
8. **Error Messages**: Help users migrate with clear error messagesQuick Install
$
npx ai-builder add skill sgcarstrends/api-versionDetails
- Type
- skill
- Author
- sgcarstrends
- Slug
- sgcarstrends/api-version
- Created
- 3d ago