Help us improve
Share bugs, ideas, or general feedback.
From coding-agent
REST API design conventions covering URL structure, HTTP methods, response formats, status codes, pagination, and versioning. Use when designing or reviewing API endpoints.
npx claudepluginhub devjarus/coding-agent --plugin coding-agentHow this skill is triggered — by the user, by Claude, or both
Slash command
/coding-agent:api-designThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
- Use nouns, never verbs: `/users`, not `/getUsers`
Provides behavioral guidelines to reduce common LLM coding mistakes, focusing on simplicity, surgical changes, assumption surfacing, and verifiable success criteria.
Searches, retrieves, and installs Agent Skills from prompts.chat registry using MCP tools like search_skills and get_skill. Activates for finding skills, browsing catalogs, or extending Claude.
Provides UI/UX resources: 50+ styles, color palettes, font pairings, guidelines, charts for web/mobile across React, Next.js, Vue, Svelte, Tailwind, React Native, Flutter. Aids planning, building, reviewing interfaces.
Share bugs, ideas, or general feedback.
/users, not /getUsers/orders, /products/users/{id}/orders is fine; avoid /users/{id}/orders/{id}/items/{id}/blog-posts, /user-profiles| Method | Semantics |
|---|---|
| GET | Read resource(s), idempotent, no body |
| POST | Create a new resource or trigger an action |
| PUT | Replace a resource entirely |
| PATCH | Partial update of a resource |
| DELETE | Remove a resource, idempotent |
Success:
{
"data": { ... },
"meta": { "requestId": "abc123", "timestamp": "2024-01-01T00:00:00Z" }
}
Error:
{
"error": {
"code": "VALIDATION_ERROR",
"message": "Human-readable description",
"details": [{ "field": "email", "issue": "Invalid format" }]
}
}
| Code | When to use |
|---|---|
| 200 | Successful GET, PUT, PATCH |
| 201 | Successful POST that created a resource |
| 204 | Successful DELETE or action with no response body |
| 400 | Bad request — malformed syntax or invalid parameters |
| 401 | Not authenticated |
| 403 | Authenticated but not authorized |
| 404 | Resource not found |
| 409 | Conflict — duplicate, state mismatch |
| 422 | Validation failed — well-formed but semantically invalid |
| 500 | Unexpected server error |
Cursor-based (for large or frequently updated datasets):
{
"data": [...],
"meta": {
"nextCursor": "eyJpZCI6MTAwfQ==",
"hasMore": true
}
}
Offset-based (for simple, small datasets):
{
"data": [...],
"meta": {
"total": 250,
"page": 2,
"perPage": 25,
"totalPages": 10
}
}
Always return a meta object even when there is only one page.
/v1/users, /v2/usersSunset response headers before removingEvery route handler should be roughly 10 lines: (1) parse input, (2) call a core function, (3) return the serialized result, (4) catch errors and map them to status codes. Business logic lives in the core library or service layer, not in the route.
// GOOD — thin wrapper around a core function
app.get('/api/posts/:slug', async (req, res, next) => {
try {
const post = await posts.findBySlug(req.params.slug);
if (!post) return res.status(404).json({ error: { code: 'NOT_FOUND', message: 'Post not found' } });
return res.status(200).json({ data: post });
} catch (err) {
return next(err);
}
});
// BAD — business logic embedded in the route
app.get('/api/posts/:slug', async (req, res) => {
const db = getDb();
const row = await db.prepare('SELECT * FROM posts WHERE slug = ?').get(req.params.slug);
if (!row) return res.status(404).json(...);
const excerpt = row.content.split('\n').slice(0, 3).join(' ').substring(0, 150); // ← logic
const tags = row.tags?.split(',') ?? []; // ← logic
return res.status(200).json({ data: { ...row, excerpt, tags } });
});
Why it matters: testing the core library is effectively testing every route, because routes add nothing beyond transport glue. If your route handler is >15 lines or contains branching business logic beyond error-to-status mapping, extract it into a pure core function and call that from the route.
Applies to: Next.js Route Handlers, Express middlewares, FastAPI endpoints, Gin handlers, Rails controllers — any framework where you're tempted to put logic "right in the handler because it's convenient."
Exception: trivial projections (e.g., picking 3 fields out of a row for a list view) are fine inline. The rule targets branching, validation, data transformation, and external calls — not one-line field selection.