You ask AI to build a user management APIWhat is api?A set of rules that lets one program talk to another, usually over the internet, by sending requests and getting responses.. It generates POST /createUser, GET /getUserById, POST /deleteUser, and GET /getAllUsers. These routes work, but they violate every RESTWhat is rest?An architectural style for web APIs where URLs represent resources (nouns) and HTTP methods (GET, POST, PUT, DELETE) represent actions on those resources. convention. Any developer consuming your API will be confused, and every new feature you add makes the naming inconsistency worse.
Resources, not actions
RESTWhat is rest?An architectural style for web APIs where URLs represent resources (nouns) and HTTP methods (GET, POST, PUT, DELETE) represent actions on those resources. APIs are organized around resources, the things your APIWhat is api?A set of rules that lets one program talk to another, usually over the internet, by sending requests and getting responses. manages. Users, books, orders, comments. The URL identifies the resource. The HTTPWhat is http?The protocol browsers and servers use to exchange web pages, API data, and other resources, defining how requests and responses are formatted. verb says what you want to do with it.
# Wrong - verbs in URLs
POST /createUser
GET /getUserById/42
POST /updateUser/42
POST /deleteUser/42
# Right - nouns in URLs, verbs are HTTP methods
POST /users (create)
GET /users/42 (read)
PUT /users/42 (update)
DELETE /users/42 (delete)| HTTP verb | URL | Action | SQL equivalent |
|---|---|---|---|
GET | /users | List all users | SELECT * FROM users |
GET | /users/42 | Get one user | SELECT * FROM users WHERE id = 42 |
POST | /users | Create a user | INSERT INTO users ... |
PUT | /users/42 | Replace a user | UPDATE users SET ... WHERE id = 42 |
PATCH | /users/42 | Partially update | UPDATE users SET name = ... WHERE id = 42 |
DELETE | /users/42 | Delete a user | DELETE FROM users WHERE id = 42 |
POST /deleteUser. You need to translate "delete a user" into DELETE /users/:id yourself, or tell the AI explicitly to follow REST conventions.Plural nouns
Resource names should always be plural, even when you are accessing a single item.
# Consistent and correct
GET /users → list of users
GET /users/42 → one user (still /users, not /user)
# Inconsistent and confusing
GET /user → list of users? one user? unclear
GET /user/42 → works, but now you have two conventionsThe rule is simple: the resource is always plural. /users/42 means "user 42 from the collection of users."
| Pattern | Example | Verdict |
|---|---|---|
| Plural nouns | /products, /orders, /reviews | Correct |
| Singular nouns | /product, /order, /review | Avoid |
| Verbs in URL | /getProducts, /createOrder | Wrong |
| Mixed casing | /userProfiles, /OrderItems | Use kebab-case instead |
| Kebab-case | /user-profiles, /order-items | Correct for multi-word resources |
Nested routes for relationships
When resources belong to other resources, nest them in the URL to express the relationship.
// Orders belonging to a specific user
app.get('/users/:userId/orders', (req, res) => {
const orders = db.findOrders({ userId: req.params.userId });
res.json(orders);
});
// A specific order belonging to a specific user
app.get('/users/:userId/orders/:orderId', (req, res) => {
const order = db.findOrder(req.params.orderId);
if (order.userId !== req.params.userId) {
return res.status(404).json({ error: 'Order not found' });
}
res.json(order);
});
// Comments on a specific post
app.get('/posts/:postId/comments', (req, res) => {
const comments = db.findComments({ postId: req.params.postId });
res.json(comments);
});Nesting should go at most two levels deep. Beyond that, the URLs become unwieldy and hard to understand.
# Good - two levels
/users/42/orders
/posts/7/comments
# Too deep - flatten instead
/users/42/orders/7/items/3/reviews # too nested
/order-items/3/reviews # better: promote to top-levelWhen to nest vs. flatten
| Relationship | Nested URL | Flat URL | Recommendation |
|---|---|---|---|
| Orders for a user | /users/:id/orders | /orders?userId=42 | Nest, strong ownership |
| Comments on a post | /posts/:id/comments | /comments?postId=7 | Either works |
| Reviews of an item | /items/:id/reviews | /reviews?itemId=3 | Either works |
| User profile picture | /users/:id/avatar | /avatars/:userId | Nest, 1:1 relationship |
If the child resource makes sense on its own (you often query reviews across all items), use a flat route with query filters. If the child only exists in context of the parent (a user's avatar), nest it.
PaginationWhat is pagination?Splitting a large set of results into smaller pages so the server and client only handle a manageable chunk at a time., filtering, and sorting
Never create separate endpoints for filtered views. Use query parameters on the collection endpointWhat is endpoint?A specific URL path on a server that handles a particular type of request, like GET /api/users..
# Pagination
GET /products?page=2&limit=20
# Filtering
GET /products?category=electronics&inStock=true
# Sorting
GET /products?sort=price&order=asc
# Combined
GET /products?category=electronics&sort=price&order=desc&page=1&limit=10Implementing pagination
app.get('/products', (req, res) => {
const page = parseInt(req.query.page) || 1;
const limit = Math.min(parseInt(req.query.limit) || 20, 100); // Cap at 100
const offset = (page - 1) * limit;
const products = db.findProducts({ offset, limit });
const total = db.countProducts();
res.json({
data: products,
pagination: {
page,
limit,
total,
totalPages: Math.ceil(total / limit)
}
});
});limit. A client can request ?limit=1000000 and your server tries to load a million records into memory. Always cap the limit.Pagination response shape
Your paginated responses should include enough metadata for the client to build pagination controls.
| Field | Purpose | Example |
|---|---|---|
data | The array of items for this page | [{...}, {...}] |
pagination.page | Current page number | 2 |
pagination.limit | Items per page | 20 |
pagination.total | Total items across all pages | 157 |
pagination.totalPages | Total number of pages | 8 |
APIWhat is api?A set of rules that lets one program talk to another, usually over the internet, by sending requests and getting responses. versioning
When you change your API in ways that break existing clients, you need versioning. The most common approach is a URL prefix.
# Version in the URL
GET /v1/users
GET /v2/users (new response format)
# In Express
const v1Router = require('./routes/v1');
const v2Router = require('./routes/v2');
app.use('/v1', v1Router);
app.use('/v2', v2Router);| Strategy | Example | Pros | Cons |
|---|---|---|---|
| URL prefix | /v1/users | Simple, obvious, easy to route | Duplicates route definitions |
| Header | Accept: application/vnd.api.v2+json | Clean URLs | Harder to test, easy to forget |
| Query param | /users?version=2 | Easy to add | Muddies the query string |
URL prefix versioning is the most common and the easiest to implement. Use it unless you have a specific reason not to.
Consistent error responses
Every error your APIWhat is api?A set of rules that lets one program talk to another, usually over the internet, by sending requests and getting responses. returns should follow the same shape. Clients should not have to guess the format.
// Consistent error format
function sendError(res, status, message, details = null) {
const response = { error: { status, message } };
if (details) response.error.details = details;
return res.status(status).json(response);
}
// Usage
app.post('/users', (req, res) => {
const { name, email } = req.body;
if (!name) return sendError(res, 400, 'Name is required');
if (!email) return sendError(res, 400, 'Email is required');
if (db.userExists(email)) {
return sendError(res, 409, 'Email already registered');
}
const user = db.createUser({ name, email });
res.status(201).json(user);
});{ error: "message" }, another returns { message: "error" }, and a third returns { success: false, msg: "..." }. Clients cannot reliably parse these. Define one error format and use it everywhere.A complete RESTWhat is rest?An architectural style for web APIs where URLs represent resources (nouns) and HTTP methods (GET, POST, PUT, DELETE) represent actions on those resources. APIWhat is api?A set of rules that lets one program talk to another, usually over the internet, by sending requests and getting responses. design checklist
When you review AI-generated API code, check each of these.
| Rule | Bad example | Good example |
|---|---|---|
| Use plural nouns | /user, /getProduct | /users, /products |
| Verbs are HTTP methods | POST /deleteUser/42 | DELETE /users/42 |
| Status codes match outcome | 200 for "not found" | 404 for "not found" |
| Consistent error format | { msg: "..." } in one place, { error: "..." } in another | { error: { status, message } } everywhere |
| Pagination has a max limit | ?limit=999999 accepted | Capped at 100 |
| Nested max 2 levels | /a/:id/b/:id/c/:id/d | /a/:id/b and /c/:id/d |
| Kebab-case URLs | /userProfiles | /user-profiles |
| Created resources return 201 | POST /users returns 200 | POST /users returns 201 |