From harness-claude
Guides REST API resource modeling: noun-based URLs, correct HTTP methods, and strategies for non-CRUD actions. Helps design predictable, self-documenting APIs.
How this skill is triggered — by the user, by Claude, or both
Slash command
/harness-claude:api-resource-modelingThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
> REST APIs are organized around resources — nouns that represent things, not verbs that represent actions. Well-modeled resources produce URLs that are predictable, cacheable, and easy to understand without documentation.
REST APIs are organized around resources — nouns that represent things, not verbs that represent actions. Well-modeled resources produce URLs that are predictable, cacheable, and easy to understand without documentation.
/getUsers violates REST conventionsResources are nouns, not verbs. The HTTP method provides the verb. The URL identifies the thing being acted upon.
| Wrong (verb in URL) | Right (noun + method) |
|---|---|
POST /createUser | POST /users |
GET /getOrder/42 | GET /orders/42 |
POST /deleteProduct/7 | DELETE /products/7 |
POST /activateAccount | POST /accounts/42/activations |
Resource identification rules:
/users (collection), /users/42 (member)./order-items, not /orderItems or /order_items. Hyphens are more readable in URLs and treated as word separators by search engines.Accept headers for content negotiation, not /users.json.Mapping domain actions to resources:
Some operations resist simple noun mapping. Common strategies:
| Domain Action | Resource Strategy | Example |
|---|---|---|
| Send a message | Create a message resource | POST /messages |
| Activate an account | Create a sub-resource for the state | POST /accounts/42/activations |
| Run a report | Create a report resource | POST /reports → GET /reports/r99 |
| Search | Use query parameters on a collection | GET /products?q=widget&category=tools |
| Merge two records | Model the merge as a resource | POST /record-merges |
The key insight: if you need to perform an action, model the result of that action as a resource. An activation is not a verb — it is a resource whose existence represents the activated state.
An e-commerce platform is adding order management endpoints. The team debates the URL structure:
Draft 1 (verb-centric):
POST /createOrder
GET /getOrder?id=42
POST /cancelOrder
POST /shipOrder
GET /listOrdersByCustomer?customerId=7
Draft 2 (resource-centric, Level 2):
POST /orders → 201 Created, Location: /orders/42
GET /orders/42 → 200 OK
POST /orders/42/cancellations → 201 Created (models the cancellation event)
POST /orders/42/shipments → 201 Created, Location: /orders/42/shipments/s1
GET /customers/7/orders → 200 OK, paginated list
Draft 2 advantages:
GET /orders/42 is cacheable. GET /getOrder?id=42 may not be (depends on the proxy, but query-only GETs are less reliably cached).GET /orders/42/cancellations to audit who cancelled and why.Handling non-CRUD actions — account verification:
A user clicks an email verification link. The action is "verify the email."
Bad: GET /verifyEmail?token=abc123 (side-effecting GET)
Bad: POST /verifyEmail (verb URL)
Good: POST /email-verifications with { "token": "abc123" } — creates a verification record and triggers the state change as a side effect.
Or if you must use a GET (for email link clicking convenience): acknowledge it violates GET safety and document it explicitly. This is a pragmatic exception, not a design template.
Verbs in URIs. /api/v1/getUserProfile, /api/v1/updatePassword, /api/v1/deleteAccount are RPC routes dressed as REST. Replace with GET /users/42/profile, PUT /users/42/password, DELETE /users/42.
Inconsistent plurality. Mixing /user/42 and /orders in the same API forces clients to memorize which resources are singular. Use plural everywhere.
Implementation details in URLs. /database/users/42 or /v2/mysql/orders leaks infrastructure. URLs should model the domain, not the implementation.
Using query parameters for resource identity. /orders?id=42 is a filter, not a resource address. The canonical address of an order is /orders/42. Query parameters are for filtering collections, not identifying members.
Deep nesting beyond two levels. /users/42/orders/7/items/3/variants/red is brittle and hard to cache. See api-nested-vs-flat for when to flatten.
Some actions genuinely cannot be modeled as nouns. REST literature calls these "controller resources" — they expose a procedural concept as a resource.
Common examples:
POST /emails/42/send — sends a draft email (the sending is the event)POST /transactions/42/void — voids a transaction (irreversible state transition)POST /search — complex search with a body payload too large for a query stringThese are acceptable when the action has no natural noun form. Document them clearly in your OpenAPI spec with a note explaining why a controller pattern was chosen. See api-openapi-design for spec conventions.
GitHub's API (api.github.com) demonstrates resource modeling at scale:
GET /repos/{owner}/{repo} — repository resource
GET /repos/{owner}/{repo}/issues — issues collection
POST /repos/{owner}/{repo}/issues — create issue
GET /repos/{owner}/{repo}/issues/42 — single issue
POST /repos/{owner}/{repo}/issues/42/comments — comment on issue
POST /repos/{owner}/{repo}/merges — merge (controller resource)
Note that /merges is a controller resource — it creates the result of a merge operation. GitHub chose this over POST /repos/{owner}/{repo}/pulls/7/merge (which they also support) to make the action explicit.
harness validate to confirm skill files are well-formed./resources (collection), /resources/{id} (member).npx claudepluginhub intense-visions/harness-engineering --plugin harness-claudeREST API design with semantic HTTP methods, status codes, and resource modeling. Use when designing new APIs or reviewing existing API designs.
Designs HTTP API endpoints following REST conventions: resource naming, HTTP methods, status codes, versioning, and response shapes.
Designs RESTful APIs with resource naming, HTTP methods, status codes, JSON response formats, pagination, and query parameters. Use when building new APIs or establishing conventions.