@databehave/server 0.1.0 → 0.1.2

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.
@@ -1,32 +0,0 @@
1
- # `server` and `basePath`
2
-
3
- ## `server`
4
-
5
- ```jsonc
6
- "server": {
7
- "host": "${MOCK_SERVER_HOST:127.0.0.1}",
8
- "port": "${MOCK_SERVER_PORT:8000}"
9
- }
10
- ```
11
-
12
- `host` defaults to `127.0.0.1`, `port` to `3000`. The CLI reads this
13
- section; the programmatic API ignores it (you pass `listen({ host,
14
- port })` directly).
15
-
16
- ## `basePath`
17
-
18
- ```jsonc
19
- "basePath": "/api/v1"
20
- ```
21
-
22
- Automatically prepended to every `endpoints` key that does NOT start
23
- with `/` after the method. Must start with `/` and must not end with
24
- `/`. OpenAPI paths are left untouched — they already carry their full
25
- path in the OAS document.
26
-
27
- ```jsonc
28
- "endpoints": {
29
- "GET products/list": "./src/list.js", // → /api/v1/products/list
30
- "GET /health": "./src/health.js" // → /health (absolute)
31
- }
32
- ```
@@ -1,161 +0,0 @@
1
- # `validation`
2
-
3
- Opt-in inbound request validation against the OpenAPI document.
4
- Disabled by default — when `validation` is omitted or
5
- `validation.request !== true`, `server.fetch(Request)` is
6
- byte-identical to the no-validation behaviour.
7
-
8
- ```jsonc
9
- "validation": {
10
- "request": true, // master switch; default false
11
- "maxBodyBytes": 102400 // default 100 KB (matches express body-parser)
12
- }
13
- ```
14
-
15
- Source: `src/types.ts:Config.validation`,
16
- `src/middleware/request-validation.ts`,
17
- `src/validation/validate.ts`.
18
-
19
- ## Field reference
20
-
21
- ### `validation.request` (boolean)
22
-
23
- Master switch. Default `false`. When `true`, every inbound request
24
- is matched against the OAS document and runs through the
25
- build-time-compiled validators below before reaching the
26
- dispatcher. Routes outside the OAS (hand-written `endpoints` keys
27
- that have no matching OAS path) are passed through unchanged — the
28
- validator has no contract to enforce.
29
-
30
- ### `validation.maxBodyBytes` (number)
31
-
32
- Hard cap on the JSON request body size, measured in **UTF-8 bytes**
33
- (not JS string length). Default `102400` (100 KB) — matches
34
- express's body-parser default. Bodies above the cap are rejected
35
- with `413 Payload Too Large` before `JSON.parse` runs. Raise only
36
- if the OpenAPI document genuinely declares large request bodies.
37
-
38
- Source: `src/middleware/request-validation.ts:42-46`,
39
- `:300-380`.
40
-
41
- ## Validation pipeline
42
-
43
- For every matching route (built once at server-creation,
44
- re-used per request) the validator runs four steps in order:
45
-
46
- 1. **Security gate** — if the OAS declares a `security` block on
47
- the operation (or globally), at least one requirement must be
48
- satisfied. Failure → `401` with a `WWW-Authenticate` challenge.
49
- Schemes recognised: `http` (presence-only `Authorization: <scheme> …`
50
- match), `apiKey` (`in: header | query`; cookie schemes are
51
- ignored), `oauth2`, `openIdConnect` (presence-only
52
- `Authorization` check; full token introspection is out of scope
53
- for a zero-dep mock — layer it via `hooks.onRequest` if needed).
54
- 2. **Content-Type guard** — for routes whose `requestBody.content`
55
- declares only `application/json`, requests with a non-JSON
56
- `Content-Type` are rejected with `415`.
57
- 3. **Body parse + validate** — the body is read once, capped at
58
- `maxBodyBytes`, then `JSON.parse`-d. Parse failure → `400`. Any
59
- schema violations are collected as `Violation[]` and emitted in
60
- the `422` response. **Body validation is strict** — no type
61
- coercion. A JSON `"42"` will not satisfy a schema with
62
- `type: integer`.
63
- 4. **Param validation (with coercion)** — query, path, and header
64
- parameters arrive as strings on the wire and are coerced
65
- (`integer`, `number`, `boolean`) before validation. Required
66
- params missing from the request emit a `required`-keyword
67
- violation. Cookie parameters are ignored.
68
-
69
- Source: `src/middleware/request-validation.ts:300-460`.
70
-
71
- ## RFC 7807 problem-detail response
72
-
73
- All rejections use `Content-Type: application/problem+json` and the
74
- shape:
75
-
76
- ```json
77
- {
78
- "type": "https://github.com/ochairo/databehave/blob/main/docs/errors/<slug>.md",
79
- "title": "Request validation failed",
80
- "status": 422,
81
- "detail": "request validation failed (3 violations)",
82
- "violations": [
83
- { "path": "/body/items/0/sku", "keyword": "minLength", "message": "..." },
84
- { "path": "/query/page", "keyword": "minimum", "message": "..." },
85
- { "path": "/header/x-id", "keyword": "required", "message": "..." }
86
- ]
87
- }
88
- ```
89
-
90
- Source: `src/middleware/request-validation.ts:24-50` (slug map +
91
- title map), `:240-280` (envelope builder).
92
-
93
- | Status | `title` | `type` slug |
94
- | --- | --- | --- |
95
- | `400` | `Malformed request` | `malformed-body` |
96
- | `401` | `Unauthorized` | `unauthorized` |
97
- | `413` | `Payload too large` | `payload-too-large` |
98
- | `415` | `Unsupported media type` | `unsupported-media-type` |
99
- | `422` | `Request validation failed` | `request-validation` |
100
-
101
- `violations` is omitted when empty (e.g. on `400` / `415` / `413`).
102
- The `Violation` shape (`{ path, keyword, message }`) is documented
103
- in `src/validation/validate.ts:Violation`. Each `path` is a
104
- JSON-Pointer rooted at one of `/body`, `/query/<name>`, `/path/<name>`,
105
- or `/header/<name>`.
106
-
107
- ## Validator scope
108
-
109
- The hand-rolled validator is intentionally a JSON-Schema **subset**
110
- (audit-it-yourself: ~600 LoC, zero dependencies). Supported
111
- keywords: `type`, `enum`, `required`, `properties`,
112
- `additionalProperties`, `items`, `pattern`, `minLength`,
113
- `maxLength`, `minimum`, `maximum`, `exclusiveMinimum`,
114
- `exclusiveMaximum`, `minItems`, `maxItems`, `$ref`
115
- (intra-document only — `#/components/schemas/...`), `oneOf`,
116
- `anyOf`, `allOf`, `discriminator`, `format` (`date`, `date-time`,
117
- `email`, `uuid`, `uri`), and `nullable` (OAS 3.0) /
118
- `["X","null"]` (OAS 3.1).
119
-
120
- Unsupported keywords are **rejected at server-start, not runtime**:
121
- `if`, `then`, `else`, `dependentSchemas`, `dependentRequired`,
122
- `unevaluatedProperties`, `unevaluatedItems`, `contentEncoding`,
123
- `contentMediaType`, `propertyNames`, `patternProperties`, and
124
- remote (`http://…` / `https://…`) `$ref`. The same set is rejected
125
- by the auto-schema translator (single source of truth on JSON
126
- Schema parity).
127
-
128
- Source: `src/validation/validate.ts:51-58` (unsupported set),
129
- `:21-44` (supported set; mirrored in
130
- `src/openapi/translate.ts`).
131
-
132
- ## Security guarantees
133
-
134
- The validator is built to be hostile-input safe:
135
-
136
- - **No `eval`, no `new Function`, no dynamic `require`** — pure
137
- recursion (`src/validation/validate.ts:18-23`).
138
- - **Prototype-pollution guard** — input objects whose own keys
139
- include `__proto__` / `constructor` / `prototype` are rejected as
140
- per-property violations (`:50-56`).
141
- - **ReDoS mitigation** — `pattern` length capped at 1024 chars;
142
- invalid regexes rejected at build time, never request time
143
- (`:42`).
144
- - **Recursion depth cap 64** — both schema build (`$ref` cycles)
145
- and `deepEqual` (used to compare against `enum` choices)
146
- (`:38-41`).
147
-
148
- ## Cross-references
149
-
150
- - Symptoms and diagnosis: [../troubleshooting.md](../troubleshooting.md).
151
- - Verbatim error catalogue (status mapping, `WWW-Authenticate`,
152
- parser errors): [../errors.md](../errors.md).
153
- - Which OAS keywords each pipeline accepts:
154
- [../openapi/keywords.md](../openapi/keywords.md).
155
- - Trust model for OAS-author input (the validator's caps are part
156
- of it): [../openapi/fallback.md#trust-model](../openapi/fallback.md#trust-model).
157
- - Bypass via custom handlers: a hand-written `endpoints` route
158
- receives the raw `Request` (post-security, post-content-type,
159
- post-body checks unless you opt out at the route level — but the
160
- route is still part of the validation universe). To skip
161
- validation entirely for a route, omit it from the OAS document.