@orchestrator-claude/definitions 3.5.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/agents/api-extractor.md +687 -0
- package/agents/business-rule-miner.md +754 -0
- package/agents/code-archaeologist.md +720 -0
- package/agents/docs-guardian.md +524 -0
- package/agents/implementer.md +512 -0
- package/agents/legacy-discoverer.md +583 -0
- package/agents/legacy-synthesizer.md +1101 -0
- package/agents/orchestrator.md +165 -0
- package/agents/planner.md +365 -0
- package/agents/researcher.md +447 -0
- package/agents/reviewer.md +514 -0
- package/agents/schema-extractor.md +781 -0
- package/agents/specifier.md +360 -0
- package/agents/task-generator.md +390 -0
- package/bin/orch-defs.js +2 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +172 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/DiffCommand.d.ts +13 -0
- package/dist/commands/DiffCommand.d.ts.map +1 -0
- package/dist/commands/DiffCommand.js +74 -0
- package/dist/commands/DiffCommand.js.map +1 -0
- package/dist/commands/SeedCommand.d.ts +19 -0
- package/dist/commands/SeedCommand.d.ts.map +1 -0
- package/dist/commands/SeedCommand.js +56 -0
- package/dist/commands/SeedCommand.js.map +1 -0
- package/dist/http/ApiClient.d.ts +50 -0
- package/dist/http/ApiClient.d.ts.map +1 -0
- package/dist/http/ApiClient.js +58 -0
- package/dist/http/ApiClient.js.map +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -0
- package/dist/manifest/ManifestLoader.d.ts +34 -0
- package/dist/manifest/ManifestLoader.d.ts.map +1 -0
- package/dist/manifest/ManifestLoader.js +110 -0
- package/dist/manifest/ManifestLoader.js.map +1 -0
- package/dist/manifest/types.d.ts +59 -0
- package/dist/manifest/types.d.ts.map +1 -0
- package/dist/manifest/types.js +5 -0
- package/dist/manifest/types.js.map +1 -0
- package/dist/scripts/generate-manifest.d.ts +10 -0
- package/dist/scripts/generate-manifest.d.ts.map +1 -0
- package/dist/scripts/generate-manifest.js +114 -0
- package/dist/scripts/generate-manifest.js.map +1 -0
- package/hooks/post-agent-artifact-relay.sh +157 -0
- package/hooks/post-artifact-generate.sh +39 -0
- package/hooks/post-implement-validate.sh +139 -0
- package/hooks/post-phase-checkpoint.sh +322 -0
- package/hooks/pre-agent-invoke.sh +34 -0
- package/hooks/pre-phase-advance.sh +40 -0
- package/hooks/track-agent-invocation.sh +241 -0
- package/kb/auth-strategies.md +742 -0
- package/kb/docs-constitution.md +310 -0
- package/kb/error-handling.md +555 -0
- package/kb/rest-conventions.md +458 -0
- package/kb/validation-patterns.md +589 -0
- package/manifest.json +314 -0
- package/package.json +65 -0
- package/skills/artifact-validator/SKILL.md +226 -0
- package/skills/docs-guardian/SKILL.md +230 -0
- package/skills/kb-lookup/SKILL.md +257 -0
- package/skills/phase-gate-evaluator/SKILL.md +274 -0
- package/skills/release/SKILL.md +239 -0
- package/skills/release/release.sh +491 -0
- package/skills/smoke-test/SKILL.md +195 -0
- package/skills/workflow-status/SKILL.md +322 -0
- package/workflows/bug-fix.json +74 -0
- package/workflows/feature-development.json +88 -0
- package/workflows/legacy-analysis.json +304 -0
- package/workflows/refactoring.json +74 -0
|
@@ -0,0 +1,458 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "REST API Conventions"
|
|
3
|
+
category: "patterns"
|
|
4
|
+
tier: "foundational"
|
|
5
|
+
tags: ["api", "rest", "http", "express"]
|
|
6
|
+
template: "api"
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# REST API Conventions
|
|
10
|
+
|
|
11
|
+
## Overview
|
|
12
|
+
|
|
13
|
+
This document defines REST API conventions and best practices for building consistent, maintainable, and scalable HTTP APIs using Express.js and Clean Architecture.
|
|
14
|
+
|
|
15
|
+
**Project**: my-project
|
|
16
|
+
**Template**: api
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## 1. HTTP Methods
|
|
21
|
+
|
|
22
|
+
### Standard Methods
|
|
23
|
+
|
|
24
|
+
| Method | Purpose | Idempotent | Safe | Success Code |
|
|
25
|
+
|--------|---------|------------|------|--------------|
|
|
26
|
+
| GET | Retrieve resource(s) | Yes | Yes | 200, 404 |
|
|
27
|
+
| POST | Create resource | No | No | 201, 400 |
|
|
28
|
+
| PUT | Replace entire resource | Yes | No | 200, 404 |
|
|
29
|
+
| PATCH | Partial update | No | No | 200, 404 |
|
|
30
|
+
| DELETE | Remove resource | Yes | No | 204, 404 |
|
|
31
|
+
|
|
32
|
+
### Best Practices
|
|
33
|
+
|
|
34
|
+
1. **GET**: Never modify state, only retrieve data
|
|
35
|
+
2. **POST**: Use for creation or non-idempotent operations
|
|
36
|
+
3. **PUT**: Requires full resource representation
|
|
37
|
+
4. **PATCH**: Use for partial updates
|
|
38
|
+
5. **DELETE**: Return 204 No Content on success
|
|
39
|
+
|
|
40
|
+
### Examples
|
|
41
|
+
|
|
42
|
+
```typescript
|
|
43
|
+
// GET - Retrieve resource
|
|
44
|
+
router.get('/api/v1/users/:id', async (req, res) => {
|
|
45
|
+
const userId = req.params.id;
|
|
46
|
+
const result = await getUserUseCase.execute({ userId });
|
|
47
|
+
|
|
48
|
+
if (result.isErr()) {
|
|
49
|
+
return res.status(404).json({ error: 'User not found' });
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
res.status(200).json(result.value);
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
// POST - Create resource
|
|
56
|
+
router.post('/api/v1/users', async (req, res) => {
|
|
57
|
+
const result = await createUserUseCase.execute(req.body);
|
|
58
|
+
|
|
59
|
+
if (result.isErr()) {
|
|
60
|
+
return res.status(400).json({ error: result.error });
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
res.status(201).json(result.value);
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
// DELETE - Remove resource
|
|
67
|
+
router.delete('/api/v1/users/:id', async (req, res) => {
|
|
68
|
+
const userId = req.params.id;
|
|
69
|
+
const result = await deleteUserUseCase.execute({ userId });
|
|
70
|
+
|
|
71
|
+
if (result.isErr()) {
|
|
72
|
+
return res.status(404).json({ error: 'User not found' });
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
res.status(204).send();
|
|
76
|
+
});
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
---
|
|
80
|
+
|
|
81
|
+
## 2. URL Structure
|
|
82
|
+
|
|
83
|
+
### Conventions
|
|
84
|
+
|
|
85
|
+
1. **Use nouns, not verbs**
|
|
86
|
+
- ✅ `/users` `/orders` `/products`
|
|
87
|
+
- ❌ `/getUsers` `/createOrder` `/deleteProduct`
|
|
88
|
+
|
|
89
|
+
2. **Use plural names**
|
|
90
|
+
- ✅ `/users` `/orders`
|
|
91
|
+
- ❌ `/user` `/order`
|
|
92
|
+
|
|
93
|
+
3. **Use kebab-case for multi-word resources**
|
|
94
|
+
- ✅ `/order-items` `/user-profiles`
|
|
95
|
+
- ❌ `/orderItems` `/userProfiles`
|
|
96
|
+
|
|
97
|
+
4. **Hierarchical structure for relationships**
|
|
98
|
+
- ✅ `/users/:userId/orders`
|
|
99
|
+
- ✅ `/posts/:postId/comments`
|
|
100
|
+
|
|
101
|
+
5. **Always include API versioning**
|
|
102
|
+
- ✅ `/api/v1/users`
|
|
103
|
+
- ❌ `/api/users`
|
|
104
|
+
|
|
105
|
+
### Examples
|
|
106
|
+
|
|
107
|
+
```
|
|
108
|
+
# Resource Collection
|
|
109
|
+
GET /api/v1/users # List users
|
|
110
|
+
POST /api/v1/users # Create user
|
|
111
|
+
|
|
112
|
+
# Single Resource
|
|
113
|
+
GET /api/v1/users/:id # Get user
|
|
114
|
+
PUT /api/v1/users/:id # Replace user
|
|
115
|
+
PATCH /api/v1/users/:id # Update user
|
|
116
|
+
DELETE /api/v1/users/:id # Delete user
|
|
117
|
+
|
|
118
|
+
# Nested Resources
|
|
119
|
+
GET /api/v1/users/:id/orders # List user's orders
|
|
120
|
+
POST /api/v1/users/:id/orders # Create order for user
|
|
121
|
+
|
|
122
|
+
# Filtering & Pagination (query params)
|
|
123
|
+
GET /api/v1/users?role=admin&page=2&limit=20
|
|
124
|
+
GET /api/v1/users?sort=name&order=asc
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
---
|
|
128
|
+
|
|
129
|
+
## 3. HTTP Status Codes
|
|
130
|
+
|
|
131
|
+
### Success Codes (2xx)
|
|
132
|
+
|
|
133
|
+
| Code | Name | Usage |
|
|
134
|
+
|------|------|-------|
|
|
135
|
+
| 200 | OK | Successful GET, PUT, PATCH |
|
|
136
|
+
| 201 | Created | Successful POST (resource created) |
|
|
137
|
+
| 204 | No Content | Successful DELETE |
|
|
138
|
+
|
|
139
|
+
### Client Error Codes (4xx)
|
|
140
|
+
|
|
141
|
+
| Code | Name | Usage |
|
|
142
|
+
|------|------|-------|
|
|
143
|
+
| 400 | Bad Request | Invalid request payload |
|
|
144
|
+
| 401 | Unauthorized | Missing or invalid auth |
|
|
145
|
+
| 403 | Forbidden | Not authorized |
|
|
146
|
+
| 404 | Not Found | Resource doesn't exist |
|
|
147
|
+
| 409 | Conflict | Resource conflict (duplicate) |
|
|
148
|
+
| 422 | Unprocessable Entity | Validation errors |
|
|
149
|
+
| 429 | Too Many Requests | Rate limit exceeded |
|
|
150
|
+
|
|
151
|
+
### Server Error Codes (5xx)
|
|
152
|
+
|
|
153
|
+
| Code | Name | Usage |
|
|
154
|
+
|------|------|-------|
|
|
155
|
+
| 500 | Internal Server Error | Unexpected error |
|
|
156
|
+
| 503 | Service Unavailable | Service down/maintenance |
|
|
157
|
+
|
|
158
|
+
### Examples
|
|
159
|
+
|
|
160
|
+
```typescript
|
|
161
|
+
// 200 OK - Successful retrieval
|
|
162
|
+
res.status(200).json({ user });
|
|
163
|
+
|
|
164
|
+
// 201 Created - Resource created
|
|
165
|
+
res.status(201).json({ user, id: newUserId });
|
|
166
|
+
|
|
167
|
+
// 204 No Content - Successful deletion
|
|
168
|
+
res.status(204).send();
|
|
169
|
+
|
|
170
|
+
// 400 Bad Request - Invalid input
|
|
171
|
+
res.status(400).json({ error: 'Invalid email format' });
|
|
172
|
+
|
|
173
|
+
// 401 Unauthorized - Missing auth
|
|
174
|
+
res.status(401).json({ error: 'Authentication required' });
|
|
175
|
+
|
|
176
|
+
// 404 Not Found - Resource doesn't exist
|
|
177
|
+
res.status(404).json({ error: 'User not found' });
|
|
178
|
+
|
|
179
|
+
// 422 Unprocessable Entity - Validation errors
|
|
180
|
+
res.status(422).json({
|
|
181
|
+
error: 'Validation failed',
|
|
182
|
+
details: validationErrors
|
|
183
|
+
});
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
---
|
|
187
|
+
|
|
188
|
+
## 4. Request/Response Headers
|
|
189
|
+
|
|
190
|
+
### Standard Request Headers
|
|
191
|
+
|
|
192
|
+
```http
|
|
193
|
+
Content-Type: application/json
|
|
194
|
+
Accept: application/json
|
|
195
|
+
Authorization: Bearer <token>
|
|
196
|
+
X-Request-Id: <uuid>
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
### Standard Response Headers
|
|
200
|
+
|
|
201
|
+
```http
|
|
202
|
+
Content-Type: application/json
|
|
203
|
+
X-Request-Id: <uuid>
|
|
204
|
+
Cache-Control: public, max-age=3600
|
|
205
|
+
ETag: "33a64df551425fcc55e4d42a148795d9f25f89d4"
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
### Example Implementation
|
|
209
|
+
|
|
210
|
+
```typescript
|
|
211
|
+
// Request ID middleware
|
|
212
|
+
app.use((req, res, next) => {
|
|
213
|
+
req.id = crypto.randomUUID();
|
|
214
|
+
res.setHeader('X-Request-Id', req.id);
|
|
215
|
+
next();
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
// Cache control for GET endpoints
|
|
219
|
+
router.get('/api/v1/users', (req, res) => {
|
|
220
|
+
res.setHeader('Cache-Control', 'public, max-age=300');
|
|
221
|
+
res.json(users);
|
|
222
|
+
});
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
---
|
|
226
|
+
|
|
227
|
+
## 5. Pagination
|
|
228
|
+
|
|
229
|
+
### Standard Query Parameters
|
|
230
|
+
|
|
231
|
+
- `page` - Page number (1-indexed)
|
|
232
|
+
- `limit` - Items per page (default: 20, max: 100)
|
|
233
|
+
- `sort` - Sort field
|
|
234
|
+
- `order` - Sort order (asc/desc)
|
|
235
|
+
|
|
236
|
+
### Response Format
|
|
237
|
+
|
|
238
|
+
```json
|
|
239
|
+
{
|
|
240
|
+
"data": [...],
|
|
241
|
+
"meta": {
|
|
242
|
+
"page": 1,
|
|
243
|
+
"limit": 20,
|
|
244
|
+
"total": 150,
|
|
245
|
+
"totalPages": 8
|
|
246
|
+
},
|
|
247
|
+
"links": {
|
|
248
|
+
"self": "/api/v1/users?page=1&limit=20",
|
|
249
|
+
"first": "/api/v1/users?page=1&limit=20",
|
|
250
|
+
"prev": null,
|
|
251
|
+
"next": "/api/v1/users?page=2&limit=20",
|
|
252
|
+
"last": "/api/v1/users?page=8&limit=20"
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
### Example Implementation
|
|
258
|
+
|
|
259
|
+
```typescript
|
|
260
|
+
router.get('/api/v1/users', async (req, res) => {
|
|
261
|
+
const page = parseInt(req.query.page as string) || 1;
|
|
262
|
+
const limit = Math.min(parseInt(req.query.limit as string) || 20, 100);
|
|
263
|
+
|
|
264
|
+
const result = await listUsersUseCase.execute({ page, limit });
|
|
265
|
+
|
|
266
|
+
if (result.isErr()) {
|
|
267
|
+
return res.status(500).json({ error: result.error });
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
const { users, total } = result.value;
|
|
271
|
+
const totalPages = Math.ceil(total / limit);
|
|
272
|
+
|
|
273
|
+
res.json({
|
|
274
|
+
data: users,
|
|
275
|
+
meta: { page, limit, total, totalPages },
|
|
276
|
+
links: {
|
|
277
|
+
self: `/api/v1/users?page=${page}&limit=${limit}`,
|
|
278
|
+
first: `/api/v1/users?page=1&limit=${limit}`,
|
|
279
|
+
prev: page > 1 ? `/api/v1/users?page=${page - 1}&limit=${limit}` : null,
|
|
280
|
+
next: page < totalPages ? `/api/v1/users?page=${page + 1}&limit=${limit}` : null,
|
|
281
|
+
last: `/api/v1/users?page=${totalPages}&limit=${limit}`,
|
|
282
|
+
},
|
|
283
|
+
});
|
|
284
|
+
});
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
---
|
|
288
|
+
|
|
289
|
+
## 6. Filtering & Sorting
|
|
290
|
+
|
|
291
|
+
### Query Parameter Conventions
|
|
292
|
+
|
|
293
|
+
```
|
|
294
|
+
# Filter by field
|
|
295
|
+
GET /api/v1/users?role=admin
|
|
296
|
+
GET /api/v1/users?status=active
|
|
297
|
+
|
|
298
|
+
# Multiple filters (AND)
|
|
299
|
+
GET /api/v1/users?role=admin&status=active
|
|
300
|
+
|
|
301
|
+
# Sort
|
|
302
|
+
GET /api/v1/users?sort=name&order=asc
|
|
303
|
+
GET /api/v1/users?sort=createdAt&order=desc
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
### Example Implementation
|
|
307
|
+
|
|
308
|
+
```typescript
|
|
309
|
+
router.get('/api/v1/users', async (req, res) => {
|
|
310
|
+
const filters = {
|
|
311
|
+
role: req.query.role as string,
|
|
312
|
+
status: req.query.status as string,
|
|
313
|
+
};
|
|
314
|
+
|
|
315
|
+
const sorting = {
|
|
316
|
+
field: (req.query.sort as string) || 'createdAt',
|
|
317
|
+
order: (req.query.order as 'asc' | 'desc') || 'desc',
|
|
318
|
+
};
|
|
319
|
+
|
|
320
|
+
const result = await listUsersUseCase.execute({ filters, sorting });
|
|
321
|
+
res.json(result.value);
|
|
322
|
+
});
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
---
|
|
326
|
+
|
|
327
|
+
## 7. HATEOAS (Hypermedia)
|
|
328
|
+
|
|
329
|
+
### Basic Link Format
|
|
330
|
+
|
|
331
|
+
```json
|
|
332
|
+
{
|
|
333
|
+
"id": "123",
|
|
334
|
+
"name": "John Doe",
|
|
335
|
+
"links": {
|
|
336
|
+
"self": "/api/v1/users/123",
|
|
337
|
+
"orders": "/api/v1/users/123/orders",
|
|
338
|
+
"profile": "/api/v1/users/123/profile"
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
### Example Implementation
|
|
344
|
+
|
|
345
|
+
```typescript
|
|
346
|
+
function addLinks(user: User, baseUrl: string) {
|
|
347
|
+
return {
|
|
348
|
+
...user,
|
|
349
|
+
links: {
|
|
350
|
+
self: `${baseUrl}/api/v1/users/${user.id}`,
|
|
351
|
+
orders: `${baseUrl}/api/v1/users/${user.id}/orders`,
|
|
352
|
+
profile: `${baseUrl}/api/v1/users/${user.id}/profile`,
|
|
353
|
+
},
|
|
354
|
+
};
|
|
355
|
+
}
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
---
|
|
359
|
+
|
|
360
|
+
## 8. Content Negotiation
|
|
361
|
+
|
|
362
|
+
### Accept Header
|
|
363
|
+
|
|
364
|
+
```http
|
|
365
|
+
Accept: application/json
|
|
366
|
+
Accept: application/xml
|
|
367
|
+
Accept: text/csv
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
### Example Implementation
|
|
371
|
+
|
|
372
|
+
```typescript
|
|
373
|
+
router.get('/api/v1/users/:id', async (req, res) => {
|
|
374
|
+
const result = await getUserUseCase.execute({ userId: req.params.id });
|
|
375
|
+
|
|
376
|
+
if (result.isErr()) {
|
|
377
|
+
return res.status(404).json({ error: 'User not found' });
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
const user = result.value;
|
|
381
|
+
|
|
382
|
+
// Content negotiation
|
|
383
|
+
if (req.accepts('json')) {
|
|
384
|
+
return res.json(user);
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
if (req.accepts('xml')) {
|
|
388
|
+
return res.type('xml').send(convertToXML(user));
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
res.status(406).json({ error: 'Not Acceptable' });
|
|
392
|
+
});
|
|
393
|
+
```
|
|
394
|
+
|
|
395
|
+
---
|
|
396
|
+
|
|
397
|
+
## 9. Versioning Strategies
|
|
398
|
+
|
|
399
|
+
### URL Versioning (Recommended)
|
|
400
|
+
|
|
401
|
+
```
|
|
402
|
+
/api/v1/users
|
|
403
|
+
/api/v2/users
|
|
404
|
+
```
|
|
405
|
+
|
|
406
|
+
**Pros**: Simple, explicit, cacheable
|
|
407
|
+
**Cons**: URL changes between versions
|
|
408
|
+
|
|
409
|
+
### Header Versioning
|
|
410
|
+
|
|
411
|
+
```http
|
|
412
|
+
Accept: application/vnd.myapi.v1+json
|
|
413
|
+
```
|
|
414
|
+
|
|
415
|
+
**Pros**: Clean URLs
|
|
416
|
+
**Cons**: Less visible, harder to test
|
|
417
|
+
|
|
418
|
+
---
|
|
419
|
+
|
|
420
|
+
## 10. Testing REST APIs
|
|
421
|
+
|
|
422
|
+
### Use Supertest
|
|
423
|
+
|
|
424
|
+
```typescript
|
|
425
|
+
import request from 'supertest';
|
|
426
|
+
import { app } from '../src/server';
|
|
427
|
+
|
|
428
|
+
describe('GET /api/v1/users/:id', () => {
|
|
429
|
+
it('should return user when found', async () => {
|
|
430
|
+
const response = await request(app)
|
|
431
|
+
.get('/api/v1/users/123')
|
|
432
|
+
.expect(200)
|
|
433
|
+
.expect('Content-Type', /json/);
|
|
434
|
+
|
|
435
|
+
expect(response.body).toHaveProperty('id', '123');
|
|
436
|
+
});
|
|
437
|
+
|
|
438
|
+
it('should return 404 when user not found', async () => {
|
|
439
|
+
await request(app)
|
|
440
|
+
.get('/api/v1/users/999')
|
|
441
|
+
.expect(404);
|
|
442
|
+
});
|
|
443
|
+
});
|
|
444
|
+
```
|
|
445
|
+
|
|
446
|
+
---
|
|
447
|
+
|
|
448
|
+
## References
|
|
449
|
+
|
|
450
|
+
- [REST API Design Best Practices](https://restfulapi.net/)
|
|
451
|
+
- [HTTP Status Codes (MDN)](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status)
|
|
452
|
+
- [Roy Fielding's Dissertation on REST](https://www.ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm)
|
|
453
|
+
|
|
454
|
+
---
|
|
455
|
+
|
|
456
|
+
**Generated for**: my-project
|
|
457
|
+
**Template**: api
|
|
458
|
+
**Constitution Preset**: orchestrator
|