Back to Skills

api-version

sgcarstrends
Updated Today
33 views
9
1
9
View on GitHub
Metaapi

About

This skill manages API versioning for Hono routes in `apps/api/src/v1/`, helping developers create new API versions and migrate endpoints between versions. It assists with deprecating old endpoints, planning breaking changes, and maintaining backward compatibility. Use it when working with versioned API routes and preparing for future API releases.

Documentation

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

mkdir -p apps/api/src/v2/routes

Step 2: Copy Existing Routes

Start with current v1 routes as a base:

cp -r apps/api/src/v1/routes/* apps/api/src/v2/routes/

Step 3: Create Version Router

Create apps/api/src/v2/index.ts:

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:

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:

// 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:

// 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:

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:

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:

// 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:

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:

# 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:

# 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:

# 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:

# 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

carsRouter.get("/", async (c) => {
  const make = c.req.query("make"); // optional
  return c.json(await getCars({ make }));
});

v2: Required parameter (breaking change)

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

{ id: 1, make: "Toyota", model: "Camry" }

v2: Nested structure (breaking change)

{
  id: 1,
  vehicle: {
    make: "Toyota",
    model: "Camry"
  }
}

Scenario 3: Rename Endpoint

v1: /cars/list v2: /cars (breaking change - URL structure)

Solution: Redirect in v1

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 messages

Quick Install

/plugin add https://github.com/sgcarstrends/sgcarstrends/tree/main/api-version

Copy and paste this command in Claude Code to install this skill

GitHub 仓库

sgcarstrends/sgcarstrends
Path: .claude/skills/api-version
apiaws-lambdabackendhonojob-schedulerneon-postgres

Related Skills

evaluating-llms-harness

Testing

This Claude Skill runs the lm-evaluation-harness to benchmark LLMs across 60+ standardized academic tasks like MMLU and GSM8K. It's designed for developers to compare model quality, track training progress, or report academic results. The tool supports various backends including HuggingFace and vLLM models.

View skill

langchain

Meta

LangChain is a framework for building LLM applications using agents, chains, and RAG pipelines. It supports multiple LLM providers, offers 500+ integrations, and includes features like tool calling and memory management. Use it for rapid prototyping and deploying production systems like chatbots, autonomous agents, and question-answering services.

View skill

huggingface-accelerate

Development

HuggingFace Accelerate provides the simplest API for adding distributed training to PyTorch scripts with just 4 lines of code. It offers a unified interface for multiple distributed training frameworks like DeepSpeed, FSDP, and DDP while handling automatic device placement and mixed precision. This makes it ideal for developers who want to quickly scale their PyTorch training across multiple GPUs or nodes without complex configuration.

View skill

nestjs

Meta

This skill provides NestJS development standards and architectural patterns for building domain-centric applications. It covers modular design, dependency injection, decorator patterns, and key framework features like controllers, services, middleware, and interceptors. Use it when developing NestJS applications, implementing APIs, configuring microservices, or integrating with databases.

View skill