api-versioning
Skill0 starsChanged 25 days agoMITView on GitHub
Provides expert knowledge for designing, implementing, and managing REST API versioning strategies with deprecation workflows.
12 other projects use a version of this.
Adopted by
Most recently taken up by
- codewithmukesh/dotnet-claude-kittheir own version, first seen Nov 8, 2026
- jars-demo/jars-skillstheir own version, first seen Oct 25, 2026
- qyndex/claude-inittheir own version, first seen Oct 13, 2026
- NoorQureshi/ronintheir own version, first seen Oct 11, 2026
- NoorQureshi/SploitAgenttheir own version, first seen Oct 11, 2026
- NoorQureshi/security-skillstheir own version, first seen Oct 11, 2026
Used with
Projects with it also use dependency-injection, openapi and 2 more.
Other files people use alongside this one.
Files found in the same public projects as a version of this one, more often than they turn up anywhere else. Each project counts once, large collections count for less, and this file's own repository is left out.
HamzaSheikh768Skilldependency-injection
Leverages FastAPI's powerful Depends system for reusable authentication, database sessions, rate limiting, and business logic injection.
Also in 3 projects that use this
ffsshhttiikkSkillopenapi
OpenAPI/Swagger specification and documentation
Also in 3 projects that use this
diego-tobalinaSkilllogging
Logging best practices for Java (SLF4J/Logback) and Node.js (Winston/Pino). Use for structured logging, log levels, and avoiding sensitive data exposure.
Also in 3 projects that use this
JohnJBorenSkillci-cd
CI/CD pipeline design, GitHub Actions, testing automation, and deployment strategies
Also in 3 projects that use this
Other versions12 projects use a version of this.
Word for word · 0
None found.
Edited · 0
None found.
Wrote their own version · 12
- codewithmukesh/dotnet-claude-kit★ 808same name
- ThibautBaissac/rails_ai_agents★ 665same name
- rrezartprebreza/spring-boot-skills★ 344same name
- Resgrid/Core★ 238same name
- NoorQureshi/security-skills★ 27same name
- NoorQureshi/ronin★ 26same name
- NoorQureshi/SploitAgent★ 26same name
- wpank/ai★ 11same name
- ffsshhttiikk/opencode-agents-skills★ 2same name
- qyndex/claude-init★ 2same name
2 more not listed
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
In this repository219 other files it gives its agents.
- .agents/AGENTS.mdAGENTS.md
- AGENTS.mdAGENTS.md
- .claude/CLAUDE.mdCLAUDE.md
- CLAUDE.mdCLAUDE.md
- .cursor/rules/behavioral-discipline.mdcCursor rule
- .cursor/rules/context-budget.mdcCursor rule
- .cursor/rules/orchestration.mdcCursor rule
- .cursor/rules/yagni-stdlib.mdcCursor rule
- androidSkill
- android-ui-designSkill
- astroSkill
- auth-token-inspectorSkill
- backlogSkill
- cc-api-contractSkill
- cc-db-migrationSkill
- cc-featureSkill
- cc-fixSkill
- cc-pagespeedSkill
- cc-refactorSkill
- cc-reviewSkill
- cc-spec-mutationSkill
- cc-tdd-cycleSkill
- cc-test-planSkill
- code-reviewSkill
- commitSkill
- conductor-setupSkill
- councilSkill
- database-migrationsSkill
- django-ormSkill
- django-testingSkill
- django-uvSkill
- drizzle-schema-architectSkill
- evaluationSkill
- fastapi-pydantic-strictSkill
- find-skillsSkill
- jpa-nplusone-detectorSkill
- jpa-postgresSkill
- laravel-specialistSkill
- livewire-alpine-bridgeSkill
- multi-agent-orchestrationSkill
- nextjs-typescriptSkill
- openspecSkill
- pagespeed-insightsSkill
- pagespeed-perfSkill
- php-proSkill
- python-django-stackSkill
- python-fastapi-stackSkill
- pythonSkill
- rust-asyncSkill
- rust-engineeringSkill
- rust-sqlxSkill
- security-ai-llmSkill
- security-blue-teamSkill
- security-cloudSkill
- security-cryptoSkill
- security-exploit-devSkill
- security-grcSkill
- security-incident-responseSkill
- security-log-analysisSkill
- security-malware-analysisSkill
- The first 60 shown.
The file
We split this skill into the rules it gives an agent
11 rules. 0 are common, 10 are distinctive, and 1 is very specific to this project.
0
Common
Most of the 4 edited versions we read keep these.
10
Distinctive
This author's own choices. Worth a look.
1
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 64
Use this when: you have breaking changes and need maximum visibility and cacheability.
- Distinctive: line 81
Use this when: you need clean URLs and your clients are all programmatic (no browsers).
- Distinctive: line 119
When a version or endpoint is being phased out, follow this process:
- Distinctive: line 157
Keep at least two active major versions at all times.
- Distinctive: line 169
Do not remove a version without a minimum 6-month notice period.
- Very specific: line 192
Use $ref to share schemas across versions without duplication.
- Distinctive: line 232
Put the breaking change in the endpoint description, not just in a changelog:
- Distinctive: line 286
Create a new controller for each new version — do not modify the existing one
- Distinctive: line 290
Never delete a versioned controller until after the sunset date
- Distinctive: line 379
Rule: run contract tests in CI before any merge that touches an API surface.
- Distinctive: line 393
Do not share test cases across versions.
“Common” is measured: kept by at least 6 in 10 of the 4 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
API Versioning
Versioning Strategies
URL Path Versioning (recommended for breaking changes)
GET /api/v1/users
GET /api/v2/usersTradeoffs:
- Explicit and visible in logs, proxies, and browser history
- Easy to cache at the CDN level — the URL uniquely identifies the resource version
- Easy to route at the load balancer
- Results in some duplication of controller code
- Changing the URL violates REST HATEOAS principles, though in practice this is acceptable
Use this when: you have breaking changes and need maximum visibility and cacheability.
Header Versioning
GET /api/users
Accept: application/vnd.myapp+json;version=1Tradeoffs:
- Cleaner URLs
- Harder to test manually — browsers and curl require extra flags
- Cannot be bookmarked or linked directly
- CDN caching requires
Vary: Acceptheader, which reduces cache hit rates
Use this when: you need clean URLs and your clients are all programmatic (no browsers).
Query Parameter Versioning (avoid)
GET /api/users?version=1This approach contaminates resource URLs with transport concerns. The version is not part of the resource identity. Do not use it. The only valid exception is temporary backward-compat support during a migration window.
When to Version
Version when the change is breaking. Not every change requires a version bump.
Breaking — requires new version:
- Removing a field from a response
- Renaming a field
- Changing a field's type (e.g.,
stringtoobject) - Changing the meaning of an existing field
- Removing an endpoint
- Changing required fields in a request
- Changing status codes in a non-additive way
Not breaking — no version bump needed:
- Adding an optional field to a response
- Adding a new endpoint
- Adding an optional request parameter
- Deprecating a field (marking it, but still returning it)
- Performance improvements
- Bug fixes that restore documented behavior
Deprecation Process
When a version or endpoint is being phased out, follow this process:
Step 1: Mark in OpenAPI.
paths:
/api/v1/users/{id}:
get:
deprecated: true
description: |
Deprecated since 2026-05-07. Use /api/v2/users/{id} instead.
Sunset date: 2026-11-07.
summary: Get user by ID (deprecated)Step 2: Add deprecation headers to responses.
@GetMapping("/{id}")
fun getUserV1(@PathVariable id: UUID, response: HttpServletResponse): ResponseEntity<UserV1Response> {
response.addHeader("Deprecation", "date=\"Wed, 07 May 2026 00:00:00 GMT\"")
response.addHeader("Sunset", "Mon, 07 Nov 2026 00:00:00 GMT")
response.addHeader("Link", "</api/v2/users/$id>; rel=\"successor-version\"")
return ResponseEntity.ok(userService.getById(id).toV1Response())
}Step 3: Document in CHANGELOG.
## Deprecated
- `GET /api/v1/users/{id}` — deprecated in favor of `GET /api/v2/users/{id}`.
Sunset: 2026-11-07.Step 4: Maintain dual support.
Keep at least two active major versions at all times. When v3 ships, v1 can be removed (v2 and v3 remain active).
Step 5: Communicate the sunset date.
Notify consumers before the sunset date through:
- API changelog
- Developer portal announcements
- Deprecation headers (machine-readable)
- Direct contact if you have consumer registration data
Do not remove a version without a minimum 6-month notice period. 3 months is the absolute minimum if forced.
OpenAPI Conventions
One file per version (simple cases)
openapi-v1.yaml
openapi-v2.yamlEach file is self-contained and independently valid.
Single file with version in info (evolving APIs)
openapi: '3.1.0'
info:
title: Users API
version: '2.0.0'Use $ref to share schemas across versions without duplication.
Cross-version schema reuse
# schemas/user-base.yaml
UserBase:
type: object
properties:
id:
type: string
format: uuid
email:
type: string
# openapi-v1.yaml
components:
schemas:
UserResponse:
allOf:
- $ref: './schemas/user-base.yaml#/UserBase'
- properties:
full_name:
type: string
# openapi-v2.yaml — splits full_name into first_name + last_name
components:
schemas:
UserResponse:
allOf:
- $ref: './schemas/user-base.yaml#/UserBase'
- properties:
first_name:
type: string
last_name:
type: stringDocumenting breaking changes
Put the breaking change in the endpoint description, not just in a changelog:
/api/v2/users/{id}:
get:
description: |
Returns user details.
Breaking changes from v1:
- `full_name` has been replaced by `first_name` and `last_name`Spring Boot Implementation
URL path versioning
// V1 controller — never modify once published
@RestController
@RequestMapping("/api/v1/users")
class UserV1Controller(private val userService: UserService) {
@GetMapping("/{id}")
@Deprecated("Use /api/v2/users/{id}", ReplaceWith("UserV2Controller.getUser()"))
fun getUser(
@PathVariable id: UUID,
response: HttpServletResponse
): ResponseEntity<UserV1Response> {
response.addHeader("Deprecation", "date=\"Wed, 07 May 2026 00:00:00 GMT\"")
response.addHeader("Sunset", "Mon, 07 Nov 2026 00:00:00 GMT")
return when (val result = userService.getById(id)) {
is UserResult.Found -> ResponseEntity.ok(result.user.toV1Response())
is UserResult.NotFound -> ResponseEntity.notFound().build()
}
}
}
// V2 controller — new version, new controller, shared service
@RestController
@RequestMapping("/api/v2/users")
class UserV2Controller(private val userService: UserService) {
@GetMapping("/{id}")
fun getUser(@PathVariable id: UUID): ResponseEntity<UserV2Response> {
return when (val result = userService.getById(id)) {
is UserResult.Found -> ResponseEntity.ok(result.user.toV2Response())
is UserResult.NotFound -> ResponseEntity.notFound().build()
}
}
}Rules:
- Create a new controller for each new version — do not modify the existing one
- The service layer is shared across versions — only the controller and DTO change
- DTO mapper functions are version-specific:
toV1Response(),toV2Response() - Never delete a versioned controller until after the sunset date
DTO versioning
// V1 — original shape
data class UserV1Response(
val id: UUID,
val email: String,
val full_name: String
)
// V2 — breaking change: split full_name
data class UserV2Response(
val id: UUID,
val email: String,
val first_name: String,
val last_name: String
)
// Extension functions for mapping
fun User.toV1Response(): UserV1Response = UserV1Response(
id = id,
email = email,
full_name = "$firstName $lastName"
)
fun User.toV2Response(): UserV2Response = UserV2Response(
id = id,
email = email,
first_name = firstName,
last_name = lastName
)Contract Testing
Contract tests verify that your API does not break existing consumers before changes reach production.
When to run: in CI, before merging any change that touches a controller, DTO, or OpenAPI spec.
Tool: Pact (consumer-driven contracts)
Consumer writes a pact:
// In the consumer service test
@ExtendWith(PactConsumerTestExt::class)
class UserServiceConsumerTest {
@Pact(consumer = "order-service", provider = "user-service")
fun getUserPact(builder: PactDslWithProvider): RequestResponsePact {
return builder
.given("user with id exists")
.uponReceiving("a request for user by id")
.path("/api/v1/users/123e4567-e89b-12d3-a456-426614174000")
.method("GET")
.willRespondWith()
.status(200)
.body(LambdaDsl.newJsonBody { body ->
body.uuid("id")
body.stringType("email")
body.stringType("full_name")
}.build())
.toPact()
}
}Provider verifies the pact:
@Provider("user-service")
@PactFolder("pacts")
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class UserServiceProviderTest {
@TestTarget
lateinit var target: HttpTestTarget
@BeforeEach
fun setUp(@LocalServerPort port: Int) {
target = HttpTestTarget("localhost", port)
}
}Rule: run contract tests in CI before any merge that touches an API surface. A broken contract test means a consumer will break in production.
Test Structure Per Version
Each API version must have its own test class:
src/test/kotlin/{package}/user/
controller/
UserV1ControllerTest.kt # tests for v1 endpoints
UserV2ControllerTest.kt # tests for v2 endpointsDo not share test cases across versions. V1 behavior must be tested independently from V2 — they can diverge.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

