What You'll Learn
- How to name REST resources
- How to structure URLs for collections, single resources, and nested resources
- When to use query parameters vs path parameters vs separate endpoints
- The conventions most public APIs follow
Why This Matters
URL design is the first thing developers see when they read your API docs. Good URLs make an API feel intuitive — developers can guess endpoints without checking docs. Bad URLs make every API call a lookup. This lesson teaches the conventions that make REST APIs predictable.
The Core Rules
1. Use plural nouns for resources
/users (not /user or /getUsers)
/posts (not /post or /listPosts)
/orders (not /order or /allOrders)
Plural nouns are consistent: /users for the collection, /users/123 for one. If you used singular, you'd have /user and /user/123 — confusing because the first sounds like one specific user.
2. Use the path to identify, the query to filter
/users/123 → 123 is the user ID (path)
/users?role=admin → role is a filter (query)
/users/123/posts → 123 is the user ID; /posts is the nested collection
3. Use lowercase with hyphens for multi-word names
/password-resets (good)
/passwordResets (acceptable but inconsistent)
/password_resets (avoid — underscores in URLs are non-standard)
/PasswordResets (avoid — case-sensitive, looks weird)
4. Version your API
/v1/users
/v2/users
Include the version in the URL. It lets you introduce breaking changes without breaking existing clients.
5. Avoid verbs in URLs
POST /users (good — "create user")
POST /createUser (bad — verb in URL)
DELETE /users/123 (good)
POST /users/123/delete (bad — verb in URL, wrong method)
The HTTP method is the verb. The URL is the noun.
6. Limit nesting to two levels
/users/123/posts (good — two levels)
/users/123/posts/456/comments (acceptable — three levels)
/users/123/posts/456/comments/789/replies (bad — too deep)
For deeper relationships, flatten with a query parameter:
GET /comments?post_id=456&user_id=123
Resource Naming Patterns
Standard CRUD
| Action | Method + URL |
|---|---|
| List | GET /resources |
| Create | POST /resources |
| Get one | GET /resources/{id} |
| Replace | PUT /resources/{id} |
| Update | PATCH /resources/{id} |
| Delete | DELETE /resources/{id} |
Nested resources
GET /users/{userId}/posts → list posts by user
POST /users/{userId}/posts → create a post for user
GET /users/{userId}/posts/{postId} → get a specific post by user
Sub-resources vs query parameters
Two ways to express the same relationship:
# Option A: nested
GET /users/123/posts
# Option B: flat with query
GET /posts?user_id=123
Both are valid. Use nesting when the sub-resource only makes sense in the context of its parent (a post cannot exist without a user). Use the flat form when the sub-resource can stand alone.
Real-World Examples
GitHub API
GET /repos/{owner}/{repo} → get a repo
GET /repos/{owner}/{repo}/issues → list issues in a repo
POST /repos/{owner}/{repo}/issues → create an issue
GET /users/{username}/repos → list a user's repos
Notice GitHub uses {owner}/{repo} instead of numeric IDs. Natural keys are fine when they are stable.
Stripe API
POST /v1/customers → create a customer
GET /v1/customers/{customer_id} → get a customer
POST /v1/customers/{customer_id}/sources → add a payment method
Stripe includes the version in the path and uses nested resources for relationships.
Actions That Don't Fit CRUD
Some operations are verbs, not CRUD. Common pattern: POST /resources/{id}/action.
POST /orders/{id}/cancel → cancel an order
POST /users/{id}/lock → lock a user account
POST /posts/{id}/publish → publish a post
POST /invoices/{id}/send → send an invoice
These are pragmatic deviations from pure REST. They are clearer than trying to force everything into CRUD.
Common Mistakes
- Mixing singular and plural.
/userfor one,/usersfor many is inconsistent. Always use plural. - Verbs in URLs.
/getUser,/createOrderbreak the REST model. Use HTTP methods instead. - Deep nesting. Past 2–3 levels, URLs become unreadable. Flatten with query parameters.
- Using underscores. Use hyphens. Underscores can be hidden by underline in browsers and are non-standard.
- Inconsistent naming. Pick a convention (lowercase-hyphenated) and apply it everywhere.
- No version prefix. Always include
/v1/so you can make breaking changes later.
Practical Exercise (5 minutes)
Design the REST endpoints for a "task management" API with these resources: users, projects, tasks, comments. List:
- The URL to list all tasks in a project.
- The URL to create a new task in a project.
- The URL to update a task's status.
- The URL to add a comment to a task.
- The URL to list all comments on a task.
- Where to put the "complete task" action — PATCH or POST /complete?
Mini Challenge
Pick any public API (Stripe, GitHub, Twitter, Slack). Read its URL structure. Identify: (1) whether it uses plural nouns, (2) how it handles nesting, (3) how it versions, (4) any action endpoints that don't fit CRUD. Most real APIs are pragmatic mixes of pure REST and action endpoints.
Key Takeaways
- Use plural nouns:
/users,/posts,/orders. - Path identifies the resource; query filters and modifies the response.
- Lowercase with hyphens for multi-word names.
- Always version:
/v1/... - Limit nesting to 2 levels; flatten deeper relationships with query parameters.
- For actions that don't fit CRUD, use
POST /resources/{id}/action.
Previously: Lesson 17 covered CRUD mapping.
Today: You learned how to design RESTful URLs and name resources.
Next: Lesson 19 covers pagination, filtering, and sorting — how to handle large collections efficiently.
FAQ
Should I use /api/ as a prefix?
Optional. Some APIs use /api/v1/users; others use /v1/users on a subdomain like api.example.com. The key is consistency — pick one and stick with it. The subdomain approach is cleaner because it separates API traffic from web traffic.
What if my resource has two IDs (composite key)?
Use nested URLs: /orgs/{org_id}/repos/{repo_id}. Or use a combined string: /repos/{org_id}-{repo_id}. The nested form is more readable and standard.
Comments
Comments
Post a Comment