@kodrunhq/opencode-autopilot 1.12.2 → 1.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/commands/oc-brainstorm.md +1 -0
- package/assets/commands/oc-new-agent.md +1 -0
- package/assets/commands/oc-new-command.md +1 -0
- package/assets/commands/oc-new-skill.md +1 -0
- package/assets/commands/oc-quick.md +1 -0
- package/assets/commands/oc-refactor.md +26 -0
- package/assets/commands/oc-review-agents.md +1 -0
- package/assets/commands/oc-review-pr.md +1 -0
- package/assets/commands/oc-security-audit.md +20 -0
- package/assets/commands/oc-stocktake.md +1 -0
- package/assets/commands/oc-tdd.md +1 -0
- package/assets/commands/oc-update-docs.md +1 -0
- package/assets/commands/oc-write-plan.md +1 -0
- package/assets/skills/api-design/SKILL.md +391 -0
- package/assets/skills/brainstorming/SKILL.md +1 -0
- package/assets/skills/code-review/SKILL.md +1 -0
- package/assets/skills/coding-standards/SKILL.md +1 -0
- package/assets/skills/csharp-patterns/SKILL.md +1 -0
- package/assets/skills/database-patterns/SKILL.md +270 -0
- package/assets/skills/docker-deployment/SKILL.md +326 -0
- package/assets/skills/e2e-testing/SKILL.md +1 -0
- package/assets/skills/frontend-design/SKILL.md +1 -0
- package/assets/skills/git-worktrees/SKILL.md +1 -0
- package/assets/skills/go-patterns/SKILL.md +1 -0
- package/assets/skills/java-patterns/SKILL.md +1 -0
- package/assets/skills/plan-executing/SKILL.md +1 -0
- package/assets/skills/plan-writing/SKILL.md +1 -0
- package/assets/skills/python-patterns/SKILL.md +1 -0
- package/assets/skills/rust-patterns/SKILL.md +1 -0
- package/assets/skills/security-patterns/SKILL.md +312 -0
- package/assets/skills/strategic-compaction/SKILL.md +1 -0
- package/assets/skills/systematic-debugging/SKILL.md +1 -0
- package/assets/skills/tdd-workflow/SKILL.md +1 -0
- package/assets/skills/typescript-patterns/SKILL.md +1 -0
- package/assets/skills/verification/SKILL.md +1 -0
- package/package.json +1 -1
- package/src/agents/db-specialist.ts +295 -0
- package/src/agents/devops.ts +352 -0
- package/src/agents/frontend-engineer.ts +541 -0
- package/src/agents/index.ts +12 -0
- package/src/agents/security-auditor.ts +348 -0
- package/src/hooks/anti-slop.ts +40 -1
- package/src/hooks/slop-patterns.ts +24 -4
- package/src/installer.ts +29 -2
- package/src/memory/capture.ts +9 -4
- package/src/memory/decay.ts +11 -0
- package/src/memory/retrieval.ts +31 -2
- package/src/orchestrator/artifacts.ts +7 -2
- package/src/orchestrator/confidence.ts +3 -2
- package/src/orchestrator/handlers/architect.ts +11 -8
- package/src/orchestrator/handlers/build.ts +12 -10
- package/src/orchestrator/handlers/challenge.ts +9 -3
- package/src/orchestrator/handlers/plan.ts +5 -4
- package/src/orchestrator/handlers/recon.ts +9 -4
- package/src/orchestrator/handlers/retrospective.ts +3 -1
- package/src/orchestrator/handlers/ship.ts +8 -7
- package/src/orchestrator/handlers/types.ts +1 -0
- package/src/orchestrator/lesson-memory.ts +2 -1
- package/src/orchestrator/orchestration-logger.ts +40 -0
- package/src/orchestrator/phase.ts +14 -0
- package/src/orchestrator/schemas.ts +1 -0
- package/src/orchestrator/skill-injection.ts +11 -6
- package/src/orchestrator/state.ts +2 -1
- package/src/review/selection.ts +4 -32
- package/src/skills/adaptive-injector.ts +96 -5
- package/src/skills/loader.ts +4 -1
- package/src/tools/orchestrate.ts +141 -18
- package/src/tools/review.ts +2 -1
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
---
|
|
2
|
+
# opencode-autopilot
|
|
3
|
+
description: Analyze and refactor code for improved design and maintainability
|
|
4
|
+
agent: coder
|
|
5
|
+
---
|
|
6
|
+
Analyze and refactor the code specified by $ARGUMENTS.
|
|
7
|
+
|
|
8
|
+
Detect the project language and framework from manifest files (package.json, tsconfig.json, go.mod, Cargo.toml, pom.xml, *.csproj, pyproject.toml, requirements.txt) and adapt refactoring patterns to that language/framework.
|
|
9
|
+
|
|
10
|
+
$ARGUMENTS can be a file path, function name, module name, or a description of what to refactor.
|
|
11
|
+
|
|
12
|
+
Apply these refactoring principles:
|
|
13
|
+
|
|
14
|
+
1. **SOLID principles** -- Single Responsibility, Open/Closed, Liskov Substitution, Interface Segregation, Dependency Inversion
|
|
15
|
+
2. **Extract functions** -- Break large functions (>50 lines) into smaller, focused units
|
|
16
|
+
3. **Reduce complexity** -- Flatten deep nesting, replace complex conditionals with early returns or strategy pattern
|
|
17
|
+
4. **Improve naming** -- Replace generic names (data, info, temp) with intention-revealing names
|
|
18
|
+
5. **Eliminate duplication** -- Extract shared logic when duplicated 3+ times
|
|
19
|
+
6. **Simplify interfaces** -- Reduce function parameters to 3 or fewer, use options objects for more
|
|
20
|
+
|
|
21
|
+
For each refactoring:
|
|
22
|
+
|
|
23
|
+
- Show the before and after code
|
|
24
|
+
- Explain why the change improves the code
|
|
25
|
+
- Run tests after each change to verify no regressions
|
|
26
|
+
- Commit with a descriptive message after tests pass
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
---
|
|
2
|
+
# opencode-autopilot
|
|
3
|
+
description: Run a security audit of recent code changes
|
|
4
|
+
agent: security-auditor
|
|
5
|
+
---
|
|
6
|
+
Audit the code specified by $ARGUMENTS for security vulnerabilities.
|
|
7
|
+
|
|
8
|
+
Detect the project language and framework from manifest files (package.json, tsconfig.json, go.mod, Cargo.toml, pom.xml, *.csproj, pyproject.toml, requirements.txt) and adapt security checks to that language/framework.
|
|
9
|
+
|
|
10
|
+
If $ARGUMENTS specifies file paths, audit those files. If $ARGUMENTS is empty or says "all", audit recent changes (use git diff to identify modified files).
|
|
11
|
+
|
|
12
|
+
Review for:
|
|
13
|
+
|
|
14
|
+
1. **OWASP Top 10** -- Injection, broken auth, sensitive data exposure, XXE, broken access control, security misconfiguration, XSS, insecure deserialization, known vulnerabilities, insufficient logging
|
|
15
|
+
2. **Hardcoded secrets** -- API keys, passwords, tokens, connection strings in source code
|
|
16
|
+
3. **Input validation** -- Missing or insufficient validation at system boundaries
|
|
17
|
+
4. **Authentication and authorization** -- Missing auth checks, weak session management, privilege escalation
|
|
18
|
+
5. **Dependency vulnerabilities** -- Run `npm audit`, `pip audit`, `cargo audit`, or equivalent
|
|
19
|
+
|
|
20
|
+
Present findings grouped by severity: CRITICAL, HIGH, MEDIUM, LOW. For each finding, include the file path, line range, issue description, and a concrete remediation with code example.
|
|
@@ -0,0 +1,391 @@
|
|
|
1
|
+
---
|
|
2
|
+
# opencode-autopilot
|
|
3
|
+
name: api-design
|
|
4
|
+
description: REST and GraphQL API design conventions covering resource naming, HTTP methods, status codes, pagination, versioning, error format, and rate limiting
|
|
5
|
+
stacks: []
|
|
6
|
+
requires: []
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# API Design Patterns
|
|
10
|
+
|
|
11
|
+
Practical conventions for designing, reviewing, and consuming REST and GraphQL APIs. Covers resource naming, HTTP method semantics, status codes, pagination, filtering, versioning, error responses, GraphQL schema design, rate limiting, idempotency, and HATEOAS. Apply these when building new APIs, reviewing API contracts, or integrating with external services.
|
|
12
|
+
|
|
13
|
+
## 1. REST Resource Naming
|
|
14
|
+
|
|
15
|
+
**DO:** Use plural nouns for collection resources. URLs represent resources, not actions.
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
GET /users # List users
|
|
19
|
+
GET /users/123 # Get user 123
|
|
20
|
+
POST /users # Create a user
|
|
21
|
+
PUT /users/123 # Replace user 123
|
|
22
|
+
PATCH /users/123 # Partially update user 123
|
|
23
|
+
DELETE /users/123 # Delete user 123
|
|
24
|
+
|
|
25
|
+
GET /users/123/orders # List orders for user 123
|
|
26
|
+
GET /orders/456 # Get order 456 directly
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
- Use kebab-case for multi-word resources: `/order-items`, `/payment-methods`
|
|
30
|
+
- Limit nesting to 2 levels: `/users/123/orders` is fine; `/users/123/orders/456/items/789/notes` is not -- flatten to `/order-items/789/notes`
|
|
31
|
+
- Use query parameters for filtering, not nested paths: `/orders?userId=123&status=pending`
|
|
32
|
+
|
|
33
|
+
**DON'T:**
|
|
34
|
+
|
|
35
|
+
- Use verbs in URLs (`/getUser`, `/createOrder`, `/deleteItem`)
|
|
36
|
+
- Use singular nouns for collections (`/user` instead of `/users`)
|
|
37
|
+
- Mix casing styles (`/orderItems` vs `/order-items`) -- pick one and be consistent
|
|
38
|
+
- Nest resources deeper than 2 levels
|
|
39
|
+
|
|
40
|
+
## 2. HTTP Method Semantics
|
|
41
|
+
|
|
42
|
+
**DO:** Use HTTP methods according to their defined semantics.
|
|
43
|
+
|
|
44
|
+
| Method | Purpose | Idempotent | Safe | Request Body |
|
|
45
|
+
|--------|---------|-----------|------|-------------|
|
|
46
|
+
| GET | Read resource(s) | Yes | Yes | No |
|
|
47
|
+
| POST | Create resource / trigger action | No | No | Yes |
|
|
48
|
+
| PUT | Replace entire resource | Yes | No | Yes |
|
|
49
|
+
| PATCH | Partial update | No* | No | Yes |
|
|
50
|
+
| DELETE | Remove resource | Yes | No | Optional |
|
|
51
|
+
|
|
52
|
+
*PATCH can be made idempotent with proper implementation (JSON Merge Patch).
|
|
53
|
+
|
|
54
|
+
- GET must never cause side effects (no writes, no state changes)
|
|
55
|
+
- PUT replaces the entire resource -- send the full representation
|
|
56
|
+
- PATCH sends only the fields to update -- use JSON Merge Patch (RFC 7396) or JSON Patch (RFC 6902)
|
|
57
|
+
- DELETE should be idempotent: deleting an already-deleted resource returns 204, not 404
|
|
58
|
+
|
|
59
|
+
**DON'T:**
|
|
60
|
+
|
|
61
|
+
- Use POST for everything (REST anti-pattern)
|
|
62
|
+
- Use GET with a request body (not reliably supported)
|
|
63
|
+
- Use PUT for partial updates (PUT means full replacement)
|
|
64
|
+
- Return different status codes for repeated DELETE calls on the same resource
|
|
65
|
+
|
|
66
|
+
## 3. Status Code Selection
|
|
67
|
+
|
|
68
|
+
**DO:** Return the most specific appropriate status code. Clients rely on status codes for control flow.
|
|
69
|
+
|
|
70
|
+
### 2xx Success
|
|
71
|
+
|
|
72
|
+
| Code | When to Use |
|
|
73
|
+
|------|------------|
|
|
74
|
+
| 200 OK | Successful GET, PUT, PATCH with response body |
|
|
75
|
+
| 201 Created | Successful POST that created a resource (include `Location` header) |
|
|
76
|
+
| 202 Accepted | Request accepted for async processing (not yet completed) |
|
|
77
|
+
| 204 No Content | Successful DELETE or PUT/PATCH with no response body |
|
|
78
|
+
|
|
79
|
+
### 3xx Redirection
|
|
80
|
+
|
|
81
|
+
| Code | When to Use |
|
|
82
|
+
|------|------------|
|
|
83
|
+
| 301 Moved Permanently | Resource URL changed permanently (cache forever) |
|
|
84
|
+
| 304 Not Modified | Conditional GET -- client cache is still valid |
|
|
85
|
+
| 307 Temporary Redirect | Temporary redirect preserving HTTP method |
|
|
86
|
+
| 308 Permanent Redirect | Permanent redirect preserving HTTP method |
|
|
87
|
+
|
|
88
|
+
### 4xx Client Errors
|
|
89
|
+
|
|
90
|
+
| Code | When to Use |
|
|
91
|
+
|------|------------|
|
|
92
|
+
| 400 Bad Request | Malformed syntax, invalid JSON, missing required field |
|
|
93
|
+
| 401 Unauthorized | Missing or invalid authentication credentials |
|
|
94
|
+
| 403 Forbidden | Authenticated but not authorized for this resource |
|
|
95
|
+
| 404 Not Found | Resource does not exist |
|
|
96
|
+
| 405 Method Not Allowed | HTTP method not supported on this endpoint |
|
|
97
|
+
| 409 Conflict | Request conflicts with current state (duplicate, version mismatch) |
|
|
98
|
+
| 415 Unsupported Media Type | Content-Type not accepted |
|
|
99
|
+
| 422 Unprocessable Entity | Valid JSON but semantic validation failed |
|
|
100
|
+
| 429 Too Many Requests | Rate limit exceeded (include `Retry-After` header) |
|
|
101
|
+
|
|
102
|
+
### 5xx Server Errors
|
|
103
|
+
|
|
104
|
+
| Code | When to Use |
|
|
105
|
+
|------|------------|
|
|
106
|
+
| 500 Internal Server Error | Unexpected server failure (log details, return generic message) |
|
|
107
|
+
| 502 Bad Gateway | Upstream service returned invalid response |
|
|
108
|
+
| 503 Service Unavailable | Server temporarily overloaded or in maintenance |
|
|
109
|
+
| 504 Gateway Timeout | Upstream service did not respond in time |
|
|
110
|
+
|
|
111
|
+
**DON'T:**
|
|
112
|
+
|
|
113
|
+
- Return 200 for errors with an error body (the "200 OK everything" anti-pattern)
|
|
114
|
+
- Return 500 for client errors (validates input before processing)
|
|
115
|
+
- Return 403 when 401 is correct (unauthenticated vs unauthorized)
|
|
116
|
+
- Return 404 to hide resource existence when 403 is more appropriate for authenticated users
|
|
117
|
+
|
|
118
|
+
## 4. Pagination
|
|
119
|
+
|
|
120
|
+
**DO:** Paginate all list endpoints. Never return unbounded collections.
|
|
121
|
+
|
|
122
|
+
### Cursor-Based (Preferred)
|
|
123
|
+
|
|
124
|
+
```
|
|
125
|
+
GET /orders?limit=20&after=dXNlcjpvcmRlcjoxMjM
|
|
126
|
+
|
|
127
|
+
Response:
|
|
128
|
+
{
|
|
129
|
+
"data": [...],
|
|
130
|
+
"pagination": {
|
|
131
|
+
"hasNextPage": true,
|
|
132
|
+
"hasPreviousPage": false,
|
|
133
|
+
"startCursor": "dXNlcjpvcmRlcjoxMDA",
|
|
134
|
+
"endCursor": "dXNlcjpvcmRlcjoxMjM"
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
- Use opaque cursors — never expose raw database IDs (sign or encrypt the payload)
|
|
140
|
+
- Cursor pagination is stable under concurrent inserts/deletes
|
|
141
|
+
- Include `hasNextPage` / `hasPreviousPage` booleans
|
|
142
|
+
|
|
143
|
+
### Offset-Based (Simpler, Less Stable)
|
|
144
|
+
|
|
145
|
+
```
|
|
146
|
+
GET /orders?page=2&limit=20
|
|
147
|
+
|
|
148
|
+
Response:
|
|
149
|
+
{
|
|
150
|
+
"data": [...],
|
|
151
|
+
"pagination": {
|
|
152
|
+
"page": 2,
|
|
153
|
+
"limit": 20,
|
|
154
|
+
"totalCount": 156,
|
|
155
|
+
"totalPages": 8
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
- Offset pagination can skip or duplicate items under concurrent writes
|
|
161
|
+
- Acceptable for admin dashboards and infrequently changing data
|
|
162
|
+
- Always include `totalCount` for UI page indicators
|
|
163
|
+
|
|
164
|
+
**DON'T:**
|
|
165
|
+
|
|
166
|
+
- Return all records in a single response (unbounded queries)
|
|
167
|
+
- Use offset pagination for real-time feeds or high-write tables
|
|
168
|
+
- Default to a page size larger than 100 (default 20-50 is reasonable)
|
|
169
|
+
- Expose raw database IDs in cursor values
|
|
170
|
+
|
|
171
|
+
## 5. Filtering and Sorting
|
|
172
|
+
|
|
173
|
+
**DO:** Use query parameters for filtering and sorting with consistent conventions.
|
|
174
|
+
|
|
175
|
+
```
|
|
176
|
+
# Filtering
|
|
177
|
+
GET /orders?status=pending&createdAfter=2024-01-01&minTotal=100
|
|
178
|
+
|
|
179
|
+
# Sorting (prefix with - for descending)
|
|
180
|
+
GET /orders?sort=-createdAt,total
|
|
181
|
+
|
|
182
|
+
# Field selection (sparse fieldsets)
|
|
183
|
+
GET /orders?fields=id,status,total,createdAt
|
|
184
|
+
|
|
185
|
+
# Combined
|
|
186
|
+
GET /orders?status=shipped&sort=-createdAt&limit=20&fields=id,status
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
- Use camelCase for query parameter names (match JSON field names)
|
|
190
|
+
- Support multiple sort fields with comma separation
|
|
191
|
+
- Use ISO 8601 for date/time filters
|
|
192
|
+
- Document all supported filter fields and operators
|
|
193
|
+
|
|
194
|
+
**DON'T:**
|
|
195
|
+
|
|
196
|
+
- Invent custom filter syntax when simple key=value works
|
|
197
|
+
- Allow filtering on unindexed columns (performance risk)
|
|
198
|
+
- Accept arbitrary field names without validation (information disclosure)
|
|
199
|
+
- Use different naming conventions for query params vs response fields
|
|
200
|
+
|
|
201
|
+
## 6. Versioning Strategies
|
|
202
|
+
|
|
203
|
+
**DO:** Version your API when making breaking changes. Pick one strategy and be consistent.
|
|
204
|
+
|
|
205
|
+
### URL Path Versioning (Most Common)
|
|
206
|
+
|
|
207
|
+
```
|
|
208
|
+
GET /v1/users/123
|
|
209
|
+
GET /v2/users/123
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
- Simple, explicit, easy to route, easy to document
|
|
213
|
+
- Recommended for public APIs and APIs with multiple consumers
|
|
214
|
+
|
|
215
|
+
### Header Versioning
|
|
216
|
+
|
|
217
|
+
```
|
|
218
|
+
GET /users/123
|
|
219
|
+
Accept: application/vnd.myapi.v2+json
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
- Keeps URLs clean
|
|
223
|
+
- Harder to test with browsers and curl
|
|
224
|
+
- Better for internal APIs with controlled clients
|
|
225
|
+
|
|
226
|
+
### Selection Guide
|
|
227
|
+
|
|
228
|
+
| Strategy | Public APIs | Internal APIs | Simplicity |
|
|
229
|
+
|----------|------------|--------------|-----------|
|
|
230
|
+
| URL path | Best | Good | Easiest |
|
|
231
|
+
| Header | Acceptable | Best | Moderate |
|
|
232
|
+
| Query param | Avoid | Acceptable | Easy |
|
|
233
|
+
|
|
234
|
+
**DON'T:**
|
|
235
|
+
|
|
236
|
+
- Break existing API contracts without versioning
|
|
237
|
+
- Maintain more than 2 active versions simultaneously
|
|
238
|
+
- Version every endpoint change -- version only for breaking changes
|
|
239
|
+
- Use date-based versions for REST APIs (confusing, hard to compare)
|
|
240
|
+
|
|
241
|
+
## 7. Error Response Format (RFC 7807)
|
|
242
|
+
|
|
243
|
+
**DO:** Use a consistent error response format across all endpoints. RFC 7807 (Problem Details) is the standard.
|
|
244
|
+
|
|
245
|
+
```json
|
|
246
|
+
{
|
|
247
|
+
"type": "https://api.example.com/errors/validation-failed",
|
|
248
|
+
"title": "Validation Failed",
|
|
249
|
+
"status": 422,
|
|
250
|
+
"detail": "The 'email' field must be a valid email address.",
|
|
251
|
+
"instance": "/users",
|
|
252
|
+
"errors": [
|
|
253
|
+
{
|
|
254
|
+
"field": "email",
|
|
255
|
+
"message": "Must be a valid email address",
|
|
256
|
+
"value": "not-an-email"
|
|
257
|
+
},
|
|
258
|
+
{
|
|
259
|
+
"field": "age",
|
|
260
|
+
"message": "Must be between 0 and 150",
|
|
261
|
+
"value": -5
|
|
262
|
+
}
|
|
263
|
+
]
|
|
264
|
+
}
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
- `type`: URI identifying the error type (documentation link)
|
|
268
|
+
- `title`: Human-readable summary (same for all instances of this type)
|
|
269
|
+
- `status`: HTTP status code (duplicated for convenience)
|
|
270
|
+
- `detail`: Human-readable explanation specific to this occurrence
|
|
271
|
+
- `instance`: URI of the request that caused the error
|
|
272
|
+
- `errors`: Array of field-level validation errors (optional, for 422 responses)
|
|
273
|
+
|
|
274
|
+
**DON'T:**
|
|
275
|
+
|
|
276
|
+
- Return different error formats from different endpoints
|
|
277
|
+
- Include stack traces or internal paths in production error responses
|
|
278
|
+
- Use generic messages without enough context to fix the problem
|
|
279
|
+
- Return error details in the response body with a 200 status code
|
|
280
|
+
|
|
281
|
+
## 8. GraphQL Schema Design
|
|
282
|
+
|
|
283
|
+
**DO:** Design GraphQL schemas for client needs with consistent patterns.
|
|
284
|
+
|
|
285
|
+
- Use input types for mutations:
|
|
286
|
+
```graphql
|
|
287
|
+
input CreateUserInput {
|
|
288
|
+
name: String!
|
|
289
|
+
email: String!
|
|
290
|
+
role: UserRole = MEMBER
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
type Mutation {
|
|
294
|
+
createUser(input: CreateUserInput!): CreateUserPayload!
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
type CreateUserPayload {
|
|
298
|
+
user: User
|
|
299
|
+
errors: [UserError!]!
|
|
300
|
+
}
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
- Use Relay-style connections for paginated lists (`OrderConnection` with `edges: [OrderEdge!]!`, `pageInfo: PageInfo!`, `totalCount: Int!`)
|
|
304
|
+
- Return mutation payloads (not raw types) for error handling and metadata
|
|
305
|
+
- Use enums for fixed sets of values (`enum OrderStatus { PENDING SHIPPED DELIVERED }`)
|
|
306
|
+
- Use interfaces and unions for polymorphic types
|
|
307
|
+
|
|
308
|
+
**DON'T:**
|
|
309
|
+
|
|
310
|
+
- Return raw types from mutations (no error handling path)
|
|
311
|
+
- Create deeply nested resolvers that cause N+1 queries (use DataLoader)
|
|
312
|
+
- Expose internal database structure directly in the schema
|
|
313
|
+
- Allow unbounded query depth -- enforce depth and complexity limits
|
|
314
|
+
|
|
315
|
+
## 9. Rate Limiting
|
|
316
|
+
|
|
317
|
+
**DO:** Implement rate limiting on all API endpoints. Communicate limits via headers.
|
|
318
|
+
|
|
319
|
+
```
|
|
320
|
+
HTTP/1.1 200 OK
|
|
321
|
+
X-RateLimit-Limit: 1000
|
|
322
|
+
X-RateLimit-Remaining: 742
|
|
323
|
+
X-RateLimit-Reset: 1672531200
|
|
324
|
+
|
|
325
|
+
HTTP/1.1 429 Too Many Requests
|
|
326
|
+
Retry-After: 30
|
|
327
|
+
X-RateLimit-Limit: 1000
|
|
328
|
+
X-RateLimit-Remaining: 0
|
|
329
|
+
X-RateLimit-Reset: 1672531200
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
- Apply per-user limits for authenticated endpoints
|
|
333
|
+
- Apply per-IP limits for unauthenticated endpoints
|
|
334
|
+
- Use sliding window or token bucket algorithms (not fixed window)
|
|
335
|
+
- Return 429 with `Retry-After` header when limit exceeded
|
|
336
|
+
- Apply stricter limits to expensive operations (search, export, batch)
|
|
337
|
+
|
|
338
|
+
**DON'T:**
|
|
339
|
+
|
|
340
|
+
- Skip rate limiting on internal APIs (internal services can overload each other)
|
|
341
|
+
- Use only IP-based limiting (shared IPs affect multiple users)
|
|
342
|
+
- Reset all limits at the same time (thundering herd)
|
|
343
|
+
- Return 403 instead of 429 for rate limiting (403 means forbidden, not throttled)
|
|
344
|
+
|
|
345
|
+
## 10. Idempotency
|
|
346
|
+
|
|
347
|
+
**DO:** Support idempotency for non-idempotent operations (POST) to handle retries safely.
|
|
348
|
+
|
|
349
|
+
```
|
|
350
|
+
POST /payments
|
|
351
|
+
Idempotency-Key: 550e8400-e29b-41d4-a716-446655440000
|
|
352
|
+
Content-Type: application/json
|
|
353
|
+
|
|
354
|
+
{
|
|
355
|
+
"amount": 99.99,
|
|
356
|
+
"currency": "USD"
|
|
357
|
+
}
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
- Accept an `Idempotency-Key` header on POST requests
|
|
361
|
+
- Store the key with the response for a retention period (e.g., 24 hours)
|
|
362
|
+
- Return the stored response for duplicate keys (same key = same response)
|
|
363
|
+
- Use UUIDv4 for idempotency keys
|
|
364
|
+
|
|
365
|
+
**DON'T:**
|
|
366
|
+
|
|
367
|
+
- Ignore duplicate requests without idempotency (double charges, duplicate records)
|
|
368
|
+
- Use request body hashing as a substitute for explicit idempotency keys
|
|
369
|
+
- Keep idempotency records forever (set a TTL)
|
|
370
|
+
- Return different status codes for replayed requests vs original
|
|
371
|
+
|
|
372
|
+
## 11. Request and Response Best Practices
|
|
373
|
+
|
|
374
|
+
**DO:** Follow consistent conventions across all endpoints.
|
|
375
|
+
|
|
376
|
+
- Use JSON as the default format (`Content-Type: application/json`)
|
|
377
|
+
- Use camelCase for JSON field names (most common convention)
|
|
378
|
+
- Use ISO 8601 for all date/time fields: `"2024-01-15T10:30:00Z"`
|
|
379
|
+
- Return the created/updated resource in response to POST/PUT/PATCH
|
|
380
|
+
- Include a `Location` header in 201 responses: `Location: /users/456`
|
|
381
|
+
- Include HATEOAS links (`self`, action links) in responses for discoverability
|
|
382
|
+
- Use `Accept-Encoding: gzip` and compress responses over 1KB
|
|
383
|
+
- Set `Cache-Control` headers on GET responses where appropriate
|
|
384
|
+
|
|
385
|
+
**DON'T:**
|
|
386
|
+
|
|
387
|
+
- Mix camelCase and snake_case in the same API
|
|
388
|
+
- Return dates as Unix timestamps or locale-specific strings
|
|
389
|
+
- Return different response shapes for the same endpoint based on query params
|
|
390
|
+
- Omit `Content-Type` headers on responses
|
|
391
|
+
- Return `null` for missing optional fields -- omit them or use a default value
|