From harness-claude
Grades REST APIs on Richardson Maturity Model levels 0-3 (POX swamp to hypermedia controls) for design maturity evaluation, PR reviews, stakeholder explanations, and REST onboarding.
npx claudepluginhub intense-visions/harness-engineering --plugin harness-claudeThis skill uses the workspace's default tool permissions.
> The Richardson Maturity Model grades REST APIs on a four-level scale — from RPC-over-HTTP tunneling (Level 0) to full hypermedia controls (Level 3). Each level adds constraints that improve discoverability, cacheability, and client-server decoupling.
Provides REST constraints, Richardson Maturity Model, HTTP semantics, status codes, content negotiation, and GraphQL/gRPC comparisons for API audits and design.
Provides Ruby on Rails REST API guidelines to Richardson Maturity Level 3 (HATEOAS), covering resource modeling, HTTP semantics, hypermedia links, pagination, errors, and caching. Use for designing, building, reviewing, refactoring APIs.
Designs clean, consistent RESTful APIs with versioning strategies, error handling, pagination, rate limiting, and OpenAPI documentation.
Share bugs, ideas, or general feedback.
The Richardson Maturity Model grades REST APIs on a four-level scale — from RPC-over-HTTP tunneling (Level 0) to full hypermedia controls (Level 3). Each level adds constraints that improve discoverability, cacheability, and client-server decoupling.
The model, described by Leonard Richardson and popularized by Martin Fowler, defines four levels:
| Level | Name | Characteristic |
|---|---|---|
| 0 | The Swamp of POX | Single endpoint, HTTP as transport tunnel |
| 1 | Resources | Separate URLs per resource |
| 2 | HTTP Verbs | Correct method semantics (GET, POST, PUT, DELETE) |
| 3 | Hypermedia Controls | Responses include links to available next actions |
Each level is strictly additive — Level 2 requires Level 1, Level 3 requires Level 2.
Level 0 — The Swamp of POX (Plain Old XML/JSON)
A single endpoint handles all operations. The HTTP method is irrelevant; the payload specifies the action.
POST /api
Content-Type: application/json
{ "action": "getUser", "userId": 42 }
POST /api
Content-Type: application/json
{ "action": "deleteUser", "userId": 42 }
This is RPC tunneled over HTTP. There is no distinction between safe and unsafe operations. Caching is impossible (all POST). Errors arrive as 200 OK with an error payload.
Level 1 — Resources
Each resource gets its own URL. Operations are still passed in the request body, but clients can now bookmark and reason about individual resources.
POST /users/42
Content-Type: application/json
{ "action": "get" }
Improvement: resource identity is in the URL. Still not exploiting HTTP method semantics.
Level 2 — HTTP Verbs
This is the practical REST target for most production APIs. HTTP methods carry semantic meaning, and status codes communicate outcomes.
GET /users/42
HTTP/1.1 200 OK
Content-Type: application/json
{ "id": 42, "name": "Alice", "email": "alice@example.com" }
DELETE /users/42
HTTP/1.1 204 No Content
POST /users
Content-Type: application/json
{ "name": "Bob", "email": "bob@example.com" }
HTTP/1.1 201 Created
Location: /users/43
GET is safe (no side effects) and idempotent. DELETE is idempotent. POST creates a new resource and returns 201 Created with a Location header. Errors use 4xx/5xx status codes — not { "status": "error" } in a 200 body.
A medical appointment booking API at each level:
Level 0:
POST /appointmentService
{ "action": "bookAppointment", "date": "2024-03-15", "doctorId": "d7" }
POST /appointmentService
{ "action": "cancelAppointment", "appointmentId": "a42" }
Level 1:
POST /doctors/d7/appointments
{ "action": "book", "date": "2024-03-15" }
POST /appointments/a42
{ "action": "cancel" }
Level 2:
POST /doctors/d7/appointments
Content-Type: application/json
{ "date": "2024-03-15", "patientId": "p99" }
→ 201 Created, Location: /appointments/a43
DELETE /appointments/a42
→ 204 No Content
Level 3:
GET /appointments/a43
→ 200 OK
{
"id": "a43",
"date": "2024-03-15",
"status": "confirmed",
"_links": {
"self": { "href": "/appointments/a43" },
"cancel": { "href": "/appointments/a43", "method": "DELETE" },
"reschedule": { "href": "/appointments/a43/reschedule", "method": "POST" },
"doctor": { "href": "/doctors/d7" }
}
}
The Level 3 response tells the client what actions are available without out-of-band documentation. A client following the links never needs to construct URLs manually.
Claiming Level 2 while returning errors in 200 bodies. { "error": true, "message": "Not found" } with status 200 OK is a Level 0 behavior regardless of URL structure. Use 404 with a problem details body. See api-status-codes and api-error-contracts.
Skipping Level 2 to chase Level 3. Teams sometimes invest in hypermedia before establishing correct HTTP semantics. The return on Level 2 (cacheability, safe methods, standard tooling) is far larger than Level 3 for most APIs. Level 3 adds cost — implement it only when clients demonstrably benefit from link-driven navigation.
Verbs in URLs at Level 2. /users/42/delete is Level 1 behavior with a Level 2 URL structure. The method already carries the verb: DELETE /users/42.
Treating the model as a score to maximize. Most production APIs should target Level 2. Level 3 has genuine cost (response size, client complexity, cache invalidation) and genuine benefit (evolvability, discoverability) — the benefit must justify the cost for your specific API.
The majority of public APIs — Stripe, GitHub, Twilio — operate at Level 2. Level 2 unlocks:
Hypermedia controls pay off when:
GitHub's API returns _links on pull requests pointing to merge, review, and comment endpoints. The client discovers available actions from the response rather than hardcoding URLs.
A fintech platform built an "API" with a single /execute endpoint accepting { "command": "transferFunds", ... }. Every call was a POST. Every response was 200 OK (including failures). Logging could not distinguish reads from writes. A CDN sat in front and cached nothing. Migrating to Level 2 — separate resource URLs, correct methods, proper status codes — reduced error detection time from minutes (polling logs) to milliseconds (5xx alerts), and CDN hit rate increased from 0% to 61% by making GET /accounts/:id cacheable.
_links to responses following the HAL or JSON:API conventions.harness validate to confirm skill files are well-formed.200 OK with an error payload.