@precepts/standards 0.1.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.
Files changed (34) hide show
  1. package/LICENSE +30 -0
  2. package/README.md +115 -0
  3. package/package.json +40 -0
  4. package/schema/document-standard-template.md +139 -0
  5. package/schema/standards.schema.json +154 -0
  6. package/standards/integration/governance/_category_.json +1 -0
  7. package/standards/integration/governance/integration-styles.md +56 -0
  8. package/standards/integration/index.md +9 -0
  9. package/standards/integration/standards/_category_.json +1 -0
  10. package/standards/integration/standards/api/_category_.json +1 -0
  11. package/standards/integration/standards/api/error-handling.md +250 -0
  12. package/standards/integration/standards/api/resource-design.md +286 -0
  13. package/standards/integration/standards/data-formats/_category_.json +1 -0
  14. package/standards/integration/standards/data-formats/character-encoding.md +206 -0
  15. package/standards/integration/standards/data-formats/date-format.md +102 -0
  16. package/standards/integration/standards/data-formats/datetime-formats.md +265 -0
  17. package/standards/integration/standards/data-formats/monetary-format.md +61 -0
  18. package/standards/integration/standards/events/_category_.json +1 -0
  19. package/standards/integration/standards/events/event-envelope.md +270 -0
  20. package/standards/integration/standards/foundational/_category_.json +1 -0
  21. package/standards/integration/standards/foundational/naming-conventions.md +334 -0
  22. package/standards/integration/standards/observability/_category_.json +1 -0
  23. package/standards/integration/standards/observability/integration-observability.md +226 -0
  24. package/standards/integration/standards/resilience/_category_.json +1 -0
  25. package/standards/integration/standards/resilience/integration-resilience-patterns.md +291 -0
  26. package/standards/integration/standards/resilience/retry-policy.md +268 -0
  27. package/standards/integration/standards/resilience/timeout.md +269 -0
  28. package/standards/integration/standards/versioning/_category_.json +1 -0
  29. package/standards/integration/standards/versioning/backward-forward-compatibility.md +230 -0
  30. package/standards/product/Guidelines/_category_.json +1 -0
  31. package/standards/product/Guidelines/requirement-document.md +54 -0
  32. package/standards/product/index.md +9 -0
  33. package/standards/project-management/index.md +9 -0
  34. package/standards/ux/index.md +9 -0
@@ -0,0 +1,250 @@
1
+ ---
2
+ identifier: "INTG-STD-009"
3
+ name: "API Error Handling"
4
+ version: "1.0.0"
5
+ status: "MANDATORY"
6
+
7
+ domain: "INTEGRATION"
8
+ documentType: "standard"
9
+ category: "error-handling"
10
+ appliesTo: ["api", "webhooks"]
11
+
12
+ lastUpdated: "2026-03-28"
13
+ owner: "Integration Architecture Board"
14
+
15
+ standardsCompliance:
16
+ iso: []
17
+ rfc: ["RFC-9457", "RFC-9110", "RFC-2119"]
18
+ w3c: []
19
+ other: ["Zalando-RESTful-API-Guidelines", "OWASP-API-Security-Top-10"]
20
+
21
+ taxonomy:
22
+ capability: "api-design"
23
+ subCapability: "error-handling"
24
+ layer: "contract"
25
+
26
+ enforcement:
27
+ method: "automated"
28
+ validationRules:
29
+ contentType: "application/problem+json"
30
+ requiredFields: ["type", "title", "status"]
31
+ rejectionCriteria:
32
+ - "Stack traces in error responses"
33
+ - "Internal implementation details in error messages"
34
+ - "Non-standard error response format"
35
+ - "Missing correlation ID in error responses"
36
+
37
+ dependsOn: ["INTG-STD-004", "INTG-STD-008"]
38
+ supersedes: ""
39
+ ---
40
+
41
+ # Error Handling
42
+
43
+ ## Purpose
44
+
45
+ All HTTP API error responses **MUST** use the RFC 9457 Problem Details format (`application/problem+json`). This eliminates bespoke error formats, enables machine-readable error processing by clients and AI agents, and prevents information leakage. RFC 9457 obsoletes RFC 7807 and aligns with industry guidelines from Zalando, Microsoft, and Google.
46
+
47
+ ## Rules
48
+
49
+ ### R-1: Content-Type
50
+
51
+ - All error responses **MUST** use media type `application/problem+json`.
52
+ - Servers **MUST** set `Content-Type: application/problem+json` for all 4xx and 5xx responses carrying a body.
53
+ - Servers **MUST NOT** return errors using `application/json` or any other media type.
54
+
55
+ ### R-2: Required Fields
56
+
57
+ Every Problem Details response **MUST** include:
58
+
59
+ | Field | Type | Description |
60
+ | --------------- | ------- | -------------------------------------------------------- |
61
+ | `type` | string | URI reference identifying the problem type |
62
+ | `title` | string | Short, human-readable summary of the problem type |
63
+ | `status` | integer | HTTP status code (**MUST** match actual response status) |
64
+ | `detail` | string | Human-readable explanation specific to this occurrence |
65
+ | `instance` | string | URI reference identifying this specific occurrence |
66
+ | `correlationId` | string | UUID v4 for end-to-end correlation |
67
+
68
+ ### R-3: Recommended Extension Fields
69
+
70
+ The following fields **SHOULD** be included where applicable:
71
+
72
+ | Field | Type | Description |
73
+ | ----------- | ------ | ---------------------------------------------- |
74
+ | `errorCode` | string | Machine-readable error code (see R-6) |
75
+ | `timestamp` | string | ISO-8601 UTC timestamp of the error occurrence |
76
+ | `errors` | array | Per-field validation errors (see R-5) |
77
+
78
+ ### R-4: Type URI Requirements
79
+
80
+ - The `type` field **MUST** be an absolute URI following the pattern `https://{domain}/problems/{error-category}`.
81
+ - Organizations **SHOULD** host human-readable documentation at the `type` URI.
82
+ - When no specific problem type applies, `"about:blank"` **MUST** be used and `title` **SHOULD** match the standard HTTP status phrase from RFC 9110.
83
+
84
+ ### R-5: Validation Error Array
85
+
86
+ For 400 and 422 responses involving input validation, the response **MUST** include an `errors` array. Each entry **MUST** contain:
87
+
88
+ | Field | Type | Req. | Description |
89
+ | --------- | ------ | ------------ | --------------------------------------------------------- |
90
+ | `field` | string | **MUST** | JSON Pointer (RFC 6901) or dot-notation path to the field |
91
+ | `message` | string | **MUST** | Human-readable description of the validation failure |
92
+ | `code` | string | **SHOULD** | Machine-readable validation error code |
93
+ | `value` | any | **MAY** | The rejected value (**MUST NOT** include sensitive data) |
94
+
95
+ ### R-6: Machine-Readable Error Codes
96
+
97
+ - Each problem type **SHOULD** define a unique `errorCode` in `UPPER_SNAKE_CASE`.
98
+ - Error codes **MUST** be stable across releases and **MUST NOT** be removed without a major version increment.
99
+ - Error codes **SHOULD** follow the pattern `{DOMAIN}_{CATEGORY}_{SPECIFIC}` (e.g., `ORDER_VALIDATION_INVALID_QUANTITY`).
100
+
101
+ ### R-7: Correlation ID
102
+
103
+ - Every error response **MUST** include `correlationId` in the body and `X-Correlation-ID` in the response header; values **MUST** match.
104
+ - If the inbound request includes `X-Correlation-ID`, the server **MUST** propagate that value.
105
+ - If absent, the server **MUST** generate a new UUID v4.
106
+ - The `correlationId` **MUST** appear in all log entries related to the failed request.
107
+
108
+ ### R-8: Status Code Consistency
109
+
110
+ - The `status` field **MUST** match the HTTP response status code.
111
+ - Servers **MUST** use the most specific status code applicable and **MUST NOT** use generic codes (e.g., 400) when a more specific code (e.g., 422) applies.
112
+
113
+ ### R-9: HTTP Status Code Usage
114
+
115
+ | Status | Title | When to Use |
116
+ | ------ | --------------------- | ------------------------------------------------------------------------------------ |
117
+ | 400 | Bad Request | Malformed syntax, invalid JSON, missing required headers |
118
+ | 401 | Unauthorized | Missing, expired, or malformed authentication credentials |
119
+ | 403 | Forbidden | Valid credentials but insufficient permissions |
120
+ | 404 | Not Found | Requested resource does not exist |
121
+ | 409 | Conflict | State conflict (optimistic locking, duplicate creation) |
122
+ | 422 | Unprocessable Content | Well-formed but semantically invalid (business rules, field validation) |
123
+ | 429 | Too Many Requests | Rate limit exceeded; **MUST** include `Retry-After` header |
124
+ | 500 | Internal Server Error | Unexpected server failure; **MUST NOT** expose internals |
125
+ | 502 | Bad Gateway | Upstream dependency returned an invalid response |
126
+ | 503 | Service Unavailable | Temporary outage or maintenance; **SHOULD** include `Retry-After` |
127
+
128
+ Use **400** for structurally malformed requests (bad JSON, wrong content type). Use **422** for well-formed requests that violate business rules or field validation.
129
+
130
+ ### R-10: Title Stability
131
+
132
+ - The `title` field **SHOULD NOT** change between occurrences of the same problem type.
133
+ - Clients **MUST NOT** parse `title` or `detail` for programmatic decisions; use `type`, `status`, and `errorCode` instead.
134
+
135
+ ### R-11: Security Requirements
136
+
137
+ - Error responses **MUST NOT** include stack traces, exception class names, internal method names, SQL queries, database details, internal hostnames, IP addresses, file paths, or software version numbers.
138
+ - The `detail` field **MUST** describe the problem from the client's perspective, not internal state.
139
+ - For 5xx errors, `detail` **SHOULD** use a generic message and log full diagnostics server-side via `correlationId`.
140
+ - Validation error `value` fields **MUST NOT** echo sensitive data (passwords, tokens, personal identifiers).
141
+
142
+ ### R-12: Retry Guidance
143
+
144
+ - 429 responses **MUST** include a `Retry-After` header.
145
+ - 503 responses **SHOULD** include a `Retry-After` header when the outage duration is known.
146
+ - Retryable errors **MAY** include a `retryAfterSeconds` integer extension field.
147
+
148
+ ### R-13: Content Negotiation
149
+
150
+ - If a client sends `Accept: application/problem+json`, the server **MUST** respond with Problem Details JSON.
151
+ - If a client sends `Accept: application/json`, the server **SHOULD** still respond with Problem Details JSON using `Content-Type: application/problem+json`.
152
+ - XML representation (`application/problem+xml`) **MAY** be supported but is not required.
153
+
154
+ ## Examples
155
+
156
+ ### Standard Error Response
157
+
158
+ ```json
159
+ {
160
+ "type": "https://api.example.com/problems/malformed-request",
161
+ "title": "Malformed Request",
162
+ "status": 400,
163
+ "detail": "The request body contains invalid JSON. Expected a comma at position 42.",
164
+ "instance": "/logs/errors/a937b-41f2",
165
+ "correlationId": "550e8400-e29b-41d4-a716-446655440000",
166
+ "errorCode": "REQUEST_PARSE_INVALID_JSON",
167
+ "timestamp": "2026-03-28T14:30:00.000Z"
168
+ }
169
+ ```
170
+
171
+ ### Validation Error Response
172
+
173
+ ```json
174
+ {
175
+ "type": "https://api.example.com/problems/validation-error",
176
+ "title": "Validation Error",
177
+ "status": 422,
178
+ "detail": "The request contains 2 validation errors that must be corrected.",
179
+ "instance": "/logs/errors/f682g-d6h5",
180
+ "correlationId": "3c6e0b8a-9c0a-45af-9db8-0b2e1f4b5c7d",
181
+ "errorCode": "REQUEST_VALIDATION_FAILED",
182
+ "timestamp": "2026-03-28T14:35:00.000Z",
183
+ "errors": [
184
+ {
185
+ "field": "/email",
186
+ "message": "Must be a valid email address.",
187
+ "code": "FIELD_FORMAT_INVALID",
188
+ "value": "not-an-email"
189
+ },
190
+ {
191
+ "field": "/quantity",
192
+ "message": "Must be greater than zero.",
193
+ "code": "FIELD_RANGE_BELOW_MINIMUM",
194
+ "value": -5
195
+ }
196
+ ]
197
+ }
198
+ ```
199
+
200
+ ## Enforcement Rules
201
+
202
+ ### Gateway-Level
203
+
204
+ - API gateways **MUST** intercept non-compliant error responses and transform them into valid Problem Details format.
205
+ - API gateways **MUST** strip fields matching sensitive patterns (stack traces, SQL, internal paths).
206
+ - API gateways **MUST** inject `correlationId` and `X-Correlation-ID` if the backend has not provided them.
207
+
208
+ ### Build-Time
209
+
210
+ - OpenAPI specs **MUST** define `application/problem+json` for all 4xx and 5xx status codes.
211
+ - Contract tests **MUST** validate error responses conform to the Problem Details schema.
212
+ - Static analysis **SHOULD** flag error response definitions that do not reference the Problem Details schema.
213
+
214
+ ### Automated Checks
215
+
216
+ The following **MUST** be enforced at the API gateway or integration test layer:
217
+
218
+ 1. All 4xx/5xx responses have `Content-Type: application/problem+json`.
219
+ 2. Required fields (`type`, `title`, `status`, `detail`, `instance`, `correlationId`) are present.
220
+ 3. The `status` field matches the HTTP response status code.
221
+ 4. `X-Correlation-ID` header is present and matches body `correlationId`.
222
+ 5. Response bodies do not match patterns for stack traces, SQL keywords, or internal hostnames.
223
+ 6. Responses with status 400 or 422 reporting field issues include the `errors` array.
224
+
225
+ ### Rejection Criteria
226
+
227
+ CI/CD **MUST** reject: non-`application/problem+json` errors, missing required fields, sensitive data in response bodies (stack traces, SQL, internal paths, hostnames), and missing or mismatched `X-Correlation-ID` headers.
228
+
229
+ ## References
230
+
231
+ - [RFC 9457 - Problem Details for HTTP APIs](https://www.rfc-editor.org/rfc/rfc9457.html)
232
+ - [RFC 9110 - HTTP Semantics](https://www.rfc-editor.org/rfc/rfc9110.html)
233
+ - [RFC 2119](https://www.rfc-editor.org/rfc/rfc2119.html) / [RFC 6901](https://www.rfc-editor.org/rfc/rfc6901.html)
234
+ - [Zalando RESTful API Guidelines](https://opensource.zalando.com/restful-api-guidelines/) / [OWASP Error Handling](https://cheatsheetseries.owasp.org/cheatsheets/Error_Handling_Cheat_Sheet.html)
235
+
236
+ ## Rationale
237
+
238
+ **Why RFC 9457?** Current IETF standard for HTTP error responses, widely supported by frameworks and gateways, eliminating the cost of bespoke formats.
239
+
240
+ **Why require all core fields plus correlationId?** `type` enables deterministic branching, `status` survives proxy transformations, `instance` links alerts to occurrences, and `correlationId` is essential for distributed tracing.
241
+
242
+ **Why strict security rules?** OWASP identifies error information leakage as a common API vulnerability - stack traces, SQL, and hostnames aid targeted exploits.
243
+
244
+ **Why the errors[] array?** Returning all validation failures at once avoids trial-and-error loops and improves developer experience.
245
+
246
+ ## Version History
247
+
248
+ | Version | Date | Change |
249
+ | ------- | ---------- | ------------------ |
250
+ | 1.0.0 | 2026-03-28 | Initial definition |
@@ -0,0 +1,286 @@
1
+ ---
2
+ identifier: "INTG-STD-008"
3
+ name: "API Resource Design and Naming"
4
+ version: "1.0.0"
5
+ status: "MANDATORY"
6
+
7
+ domain: "INTEGRATION"
8
+ documentType: "standard"
9
+ category: "protocol"
10
+ appliesTo: ["api"]
11
+
12
+ lastUpdated: "2026-03-28"
13
+ owner: "Integration Architecture Board"
14
+
15
+ standardsCompliance:
16
+ iso: []
17
+ rfc: ["RFC-9110", "RFC-9205"]
18
+ w3c: []
19
+ other: ["Google-Cloud-API-Design-Guide", "Zalando-RESTful-API-Guidelines", "Microsoft-REST-API-Guidelines"]
20
+
21
+ taxonomy:
22
+ capability: "api-design"
23
+ subCapability: "resource-modeling"
24
+ layer: "contract"
25
+
26
+ enforcement:
27
+ method: "hybrid"
28
+ validationRules:
29
+ urlPattern: "^/v[0-9]+/[a-z][a-z0-9-]*(/{[a-z_]+}(/[a-z][a-z0-9-]*)*)*$"
30
+ rejectionCriteria:
31
+ - "Verbs in URL path segments"
32
+ - "Singular nouns for collection endpoints"
33
+ - "Missing pagination on collection endpoints"
34
+
35
+ dependsOn: ["INTG-STD-004"]
36
+ supersedes: ""
37
+ ---
38
+
39
+ # Resource Design
40
+
41
+ ## Purpose
42
+
43
+ This standard defines the required structure for RESTful API resources, URL paths, HTTP method usage, collection patterns, and operation semantics across all integration boundaries. Consistent resource design makes APIs predictable, securable, and machine-governable. Field naming within payloads is governed by INTG-STD-004; this standard covers URL structure, HTTP semantics, and collection-level patterns.
44
+
45
+ > *Normative language (**MUST**, **MUST NOT**, **SHOULD**, **MAY**) follows RFC 2119 semantics.*
46
+
47
+ ---
48
+
49
+ ## Rules
50
+
51
+ ### R-1: URL Structure
52
+
53
+ Every API URL **MUST** follow this pattern:
54
+
55
+ ```
56
+ /v{major}/{collection}/{resource_id}/{sub-collection}/{sub_resource_id}
57
+ ```
58
+
59
+ - The version prefix **MUST** be `v` + major version number as the first path segment.
60
+ - Path segments after the version **MUST** alternate between collection names and resource identifiers.
61
+ - Collection path segments **MUST** use plural nouns in kebab-case. They **MUST NOT** contain verbs.
62
+ - Resource identifier path parameter names **MUST** use snake_case (e.g., `{order_id}`).
63
+ - Identifier values **SHOULD** use a type prefix with an opaque string (e.g., `ord_82f3k`).
64
+ - Identifier values **MUST** be URL-safe and **MUST NOT** expose sequential integers as the sole identifier.
65
+ - URL paths **SHOULD NOT** exceed three levels of resource nesting.
66
+ - URLs **MUST NOT** contain trailing slashes or empty path segments.
67
+ - All API paths **MUST** match: `^/v[0-9]+/[a-z][a-z0-9-]*(/{[a-z_]+}(/[a-z][a-z0-9-]*)*)*$`
68
+
69
+ **Valid URLs:**
70
+ ```
71
+ /v1/orders
72
+ /v1/line-items
73
+ /v1/orders/ord_82f3k
74
+ /v1/users/usr_19dk2/addresses/addr_7fj29
75
+ ```
76
+
77
+ **Invalid URLs:**
78
+ ```
79
+ /v1/order # singular
80
+ /v1/getOrders # verb, camelCase
81
+ /v1/order_items # snake_case path segment
82
+ /v1/orders/12345 # sequential integer
83
+ /v1/orders/ord_82f3k/ # trailing slash
84
+ ```
85
+
86
+ ### R-2: HTTP Method Semantics
87
+
88
+ APIs **MUST** use HTTP methods per RFC 9110.
89
+
90
+ | Operation | Method | URL Target | Body | Idempotent | Safe |
91
+ |-----------|--------|------------|------|------------|------|
92
+ | List collection | `GET` | `/v1/resources` | None | Yes | Yes |
93
+ | Get resource | `GET` | `/v1/resources/{id}` | None | Yes | Yes |
94
+ | Create resource | `POST` | `/v1/resources` | Resource | No | No |
95
+ | Full replace | `PUT` | `/v1/resources/{id}` | Complete | Yes | No |
96
+ | Partial update | `PATCH` | `/v1/resources/{id}` | Partial | No* | No |
97
+ | Delete resource | `DELETE` | `/v1/resources/{id}` | None | Yes | No |
98
+
99
+ *PATCH **SHOULD** be designed to be idempotent where possible.
100
+
101
+ - `GET` **MUST** be safe and **MUST NOT** accept a request body. Responses **MUST** be cacheable unless marked otherwise.
102
+ - `POST` to a collection **MUST** return `201 Created` with a `Location` header. POST **SHOULD** accept an `Idempotency-Key` header for safe retries.
103
+ - `PUT` **MUST** replace the entire resource and **MUST** be idempotent. Omitted fields **MUST** reset to defaults.
104
+ - `PATCH` **MUST** use JSON Merge Patch (RFC 7396). Only fields present **MUST** be updated; absent fields **MUST** remain unchanged. To null a field, send JSON `null`.
105
+ - `DELETE` **MUST** be idempotent and **MUST NOT** accept a request body. Return `204 No Content` or `200 OK`.
106
+ - `GET` and `DELETE` **MUST NOT** accept a request body. `POST` **MUST NOT** be used for retrieval. `PUT` **MUST NOT** be used for partial updates.
107
+
108
+ ### R-3: Collection Response Envelope
109
+
110
+ All collection responses **MUST** return a JSON object (never a bare array) with these fields:
111
+
112
+ | Field | Type | Required | Description |
113
+ |-------|------|----------|-------------|
114
+ | `data` | array | **MUST** | The array of resource objects |
115
+ | `pagination` | object | **MUST** | Pagination metadata |
116
+
117
+ **Valid collection response:**
118
+ ```json
119
+ {
120
+ "data": [
121
+ { "id": "ord_82f3k", "status": "confirmed" },
122
+ { "id": "ord_93g4l", "status": "draft" }
123
+ ],
124
+ "pagination": {
125
+ "has_more": true,
126
+ "next_cursor": "eyJpZCI6Im9yZF85M2c0bCJ9"
127
+ }
128
+ }
129
+ ```
130
+
131
+ ### R-4: Pagination
132
+
133
+ All collection endpoints **MUST** support pagination. Cursor-based pagination **MUST** be the default. Offset-based pagination (`?page=`, `?offset=`) **MUST NOT** be used.
134
+
135
+ **Cursor request parameters:**
136
+
137
+ | Parameter | Type | Description |
138
+ |-----------|------|-------------|
139
+ | `limit` | integer | Max items to return. **MUST** default to a service-defined value (recommended: 20). **MUST NOT** exceed 100. |
140
+ | `starting_after` | string | Return items after this resource ID |
141
+ | `ending_before` | string | Return items before this resource ID |
142
+
143
+ `starting_after` and `ending_before` are mutually exclusive; sending both **MUST** return `400 Bad Request`.
144
+
145
+ **Cursor response fields:**
146
+
147
+ | Field | Type | Description |
148
+ |-------|------|-------------|
149
+ | `has_more` | boolean | `true` if additional items exist beyond this page |
150
+ | `next_cursor` | string or null | Opaque cursor for next page. `null` when `has_more` is `false`. |
151
+
152
+ Collection endpoints **SHOULD NOT** return `total_count` by default. If required, it **MAY** be opt-in via `?include_total=true`.
153
+
154
+ ### R-5: Filtering and Sorting
155
+
156
+ Filtering **MUST** use query parameters with snake_case names. Range operators **SHOULD** use suffixed names:
157
+
158
+ | Suffix | Meaning | Example |
159
+ |--------|---------|---------|
160
+ | (none) | Exact match | `?status=confirmed` |
161
+ | `_gt`, `_gte` | Greater than (or equal) | `?created_at_gt=2026-03-01T00:00:00Z` |
162
+ | `_lt`, `_lte` | Less than (or equal) | `?amount_lte=500` |
163
+ | `_ne` | Not equal | `?status_ne=cancelled` |
164
+ | `_in` | In set (comma-separated) | `?status_in=draft,confirmed` |
165
+
166
+ Sorting **MUST** use the `sort` query parameter with field names optionally prefixed by `-` for descending. Multiple fields **MUST** be comma-separated. Default sort **MUST** be stable.
167
+
168
+ ### R-6: Field Selection and Expansion
169
+
170
+ APIs **MAY** support `fields` (comma-separated field names) for sparse fieldsets. The `id` field **MUST** always be included regardless.
171
+
172
+ APIs **MAY** support `expand` (comma-separated relationship names) to inline related resources. Expansion depth **MUST** be limited to one level - nested expansion **MUST NOT** be supported.
173
+
174
+ ### R-7: Sub-resources
175
+
176
+ A resource **MUST** be modeled as a sub-resource only when it cannot exist without its parent, is never accessed independently, and shares authorization context with its parent. Otherwise it **SHOULD** be a top-level resource with a foreign key reference.
177
+
178
+ Singleton sub-resources (one instance per parent) **MUST** use a singular noun, **MUST** support `GET` and `PUT`/`PATCH`, and **MUST NOT** support `POST`, `DELETE`, or list operations independently.
179
+
180
+ ### R-8: Bulk Operations
181
+
182
+ Bulk operations **MUST** use `POST /v1/{collection}:bulk-{verb}`. The request **MUST** contain an array of identifiers or representations. The response **MUST** return per-item results including individual success or failure. Maximum item count **MUST** be enforced (recommended: 100).
183
+
184
+ Batch operations (heterogeneous) **SHOULD** be avoided. If required, the endpoint **MUST** be `/v1/batch` and the response **MUST** use `207 Multi-Status`.
185
+
186
+ ### R-9: Long-running Operations
187
+
188
+ Operations that cannot complete synchronously **MUST** return `202 Accepted` with an `Operation-Location` header pointing to a status monitor resource. The status field **MUST** use one of: `pending`, `running`, `succeeded`, `failed`, `cancelled`. The server **SHOULD** return a `Retry-After` header. On completion, the response **MUST** include `result` (success) or `error` (failure). Cancellation **SHOULD** be supported via `POST /v1/operations/{op_id}:cancel`.
189
+
190
+ ### R-10: Security
191
+
192
+ - Resource identifiers **MUST NOT** be sequential integers. Use opaque, high-entropy identifiers.
193
+ - Authorization checks **MUST** occur on every request. Sub-resource access **MUST** validate the parent chain.
194
+ - Error responses **MUST NOT** distinguish between "does not exist" and "no access" - return `404` (or `403` consistently) for both.
195
+ - Collection endpoints **MUST** apply authorization filters before pagination.
196
+ - URLs **MUST NOT** contain PII or sensitive data.
197
+
198
+ ### R-11: Content Types
199
+
200
+ | Operation | Content-Type | Notes |
201
+ |-----------|-------------|-------|
202
+ | Request body (create/update) | `application/json` | **MUST** be the default |
203
+ | PATCH request body | `application/merge-patch+json` | **MUST** for JSON Merge Patch |
204
+ | Response body | `application/json` | **MUST** be the default |
205
+
206
+ ---
207
+
208
+ ## Examples
209
+
210
+ ### Valid API resource structure
211
+
212
+ ```
213
+ GET /v1/orders # List orders (paginated)
214
+ GET /v1/orders/{order_id} # Get single order
215
+ POST /v1/orders # Create order
216
+ GET /v1/orders/{order_id}/items # List items in order
217
+ POST /v1/orders:bulk-cancel # Bulk action on orders
218
+ ```
219
+
220
+ ### Invalid API resource structure
221
+
222
+ ```
223
+ GET /v1/getOrders # Verb in path
224
+ GET /v1/order/123 # Singular collection name
225
+ POST /v1/orders/123/cancel # Action as sub-resource
226
+ GET /api/v1/orders # Redundant /api prefix
227
+ GET /v1/orders/ # Trailing slash
228
+ ```
229
+
230
+ ## Enforcement Rules
231
+
232
+ The following **MUST** be rejected at API gateway or design review:
233
+
234
+ 1. **Verbs in URL paths** - path segments containing action words (e.g., `get`, `create`, `delete`).
235
+ 2. **Singular collection names** - collection path segments that are not plural.
236
+ 3. **Missing pagination** - collection endpoints returning unbounded arrays.
237
+ 4. **Offset-based pagination** - use of `page`, `offset`, or `skip` query parameters.
238
+ 5. **Sequential integer identifiers** - predictable sequential resource IDs.
239
+ 6. **Request body on GET or DELETE** - any GET or DELETE accepting a body.
240
+ 7. **PII in URLs** - email addresses, names, or personal data in path segments.
241
+ 8. **Bare array responses** - collections returning a JSON array instead of `{"data": [], "pagination": {}}`.
242
+ 9. **URL path validation** - all paths **MUST** match: `^/v[0-9]+/[a-z][a-z0-9-]*(/{[a-z_]+}(/[a-z][a-z0-9-]*)*)*$`
243
+ 10. **Collection response validation** - `data` **MUST** be an array, `pagination` **MUST** be an object, `pagination.has_more` **MUST** be a boolean.
244
+ 11. **POST to collection** - **MUST** return `201`.
245
+ 12. **PUT idempotency** - repeated identical requests **MUST** produce the same result.
246
+
247
+ Enforcement **MUST** occur at two stages: design time (OpenAPI linting) and runtime (API gateway validation).
248
+
249
+ ---
250
+
251
+ ## References
252
+
253
+ - [RFC 9110 - HTTP Semantics](https://www.rfc-editor.org/rfc/rfc9110)
254
+ - [RFC 9205 - Building Protocols with HTTP](https://www.rfc-editor.org/rfc/rfc9205)
255
+ - [RFC 7396 - JSON Merge Patch](https://www.rfc-editor.org/rfc/rfc7396)
256
+ - [Google AIP-121 - Resource-oriented Design](https://google.aip.dev/121)
257
+ - [Zalando RESTful API Guidelines](https://opensource.zalando.com/restful-api-guidelines/)
258
+ - [Microsoft REST API Guidelines](https://github.com/microsoft/api-guidelines)
259
+ - [OWASP API Security - BOLA](https://owasp.org/API-Security/editions/2023/en/0xa1-broken-object-level-authorization/)
260
+ - INTG-STD-004 - Naming Conventions
261
+
262
+ ---
263
+
264
+ ## Rationale
265
+
266
+ **Resource-oriented design over RPC** - Modeling APIs as resources with standard methods reduces cognitive load; learn one resource, understand them all.
267
+
268
+ **Cursor-based pagination** - Offset pagination breaks under concurrent writes (items shift between pages). Cursor pagination provides stable traversal at any scale.
269
+
270
+ **Opaque identifiers** - Sequential integers are trivially enumerable and enable BOLA attacks. Prefixed opaque IDs provide type safety and security.
271
+
272
+ **Kebab-case URLs, snake_case parameters** - Kebab-case is readable in logs and browsers. Snake_case in parameters aligns with JSON field naming per INTG-STD-004.
273
+
274
+ **Collection envelope** - `{"data": [], "pagination": {}}` ensures pagination metadata can be added without breaking changes.
275
+
276
+ **JSON Merge Patch** - Simpler than JSON Patch (RFC 6902) for common partial updates, using natural JSON structure rather than operation arrays.
277
+
278
+ **Long-running operations as resources** - Treating operations as pollable resources follows the same pattern used throughout the API, avoiding WebSocket complexity.
279
+
280
+ ---
281
+
282
+ ## Version History
283
+
284
+ | Version | Date | Change |
285
+ | ------- | ---------- | ------------------ |
286
+ | 1.0.0 | 2026-03-28 | Initial definition |
@@ -0,0 +1 @@
1
+ {"label": "Data Formats", "position": 2}