From harness-claude
Guides REST API resource modeling with nouns for URLs and HTTP methods for actions. Use for designing endpoints, reviewing PRs, refactoring RPC APIs, and mapping domain concepts to HTTP.
npx claudepluginhub intense-visions/harness-engineering --plugin harness-claudeThis skill uses the workspace's default tool permissions.
> 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.
Design RESTful APIs following best practices for resource modeling, HTTP methods, status codes, versioning, and OpenAPI documentation. Use when creating new APIs, designing endpoints, or improving existing API architecture.
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.
Guides RESTful API design and implementation: resource naming, HTTP methods, URL patterns, error responses, versioning, and core principles.
Share bugs, ideas, or general feedback.
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).