express-version-api 2.0.4 → 2.0.5
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/CHANGELOG.md +23 -0
- package/README.md +157 -78
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,29 @@ and this project adheres to [Semantic Versioning](https://semver.org/).
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [2.0.4] - 2026-02-27
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- Added `jsr.json` configuration and JSR package metadata.
|
|
15
|
+
- Added JSR publication support for `@braian-quintian/express-version-api`.
|
|
16
|
+
|
|
17
|
+
### Changed
|
|
18
|
+
|
|
19
|
+
- Updated repository documentation to match the current runtime behavior and exports.
|
|
20
|
+
- Hardened release automation to validate npm authentication before publish.
|
|
21
|
+
|
|
22
|
+
### Fixed
|
|
23
|
+
|
|
24
|
+
- Fixed `.npmrc` token interpolation to use `NODE_AUTH_TOKEN` in CI.
|
|
25
|
+
- Fixed GitHub Packages publication flow by using scoped package publish in workflow.
|
|
26
|
+
|
|
27
|
+
## [2.0.3] - 2026-02-27
|
|
28
|
+
|
|
29
|
+
### Changed
|
|
30
|
+
|
|
31
|
+
- Updated release workflow with explicit npm authentication verification.
|
|
32
|
+
|
|
10
33
|
## [2.0.0] - 2026-02-27
|
|
11
34
|
|
|
12
35
|
### Removed
|
package/README.md
CHANGED
|
@@ -5,14 +5,30 @@
|
|
|
5
5
|
[](https://github.com/Braian-Quintian/express-version-api/actions)
|
|
6
6
|
[](./LICENSE)
|
|
7
7
|
|
|
8
|
-
Version-aware middleware for Express.js with semantic version matching.
|
|
8
|
+
Version-aware middleware for Express.js APIs with semantic version matching.
|
|
9
|
+
|
|
10
|
+
## Why use this
|
|
11
|
+
|
|
12
|
+
- Routes requests by semantic version (`exact`, `~`, `^`).
|
|
13
|
+
- Supports extraction from header, query, path, or custom function.
|
|
14
|
+
- Handles missing or unmatched versions with configurable fallback strategies.
|
|
15
|
+
- Exposes `req.versionInfo` metadata for observability and debugging.
|
|
16
|
+
- Fully typed for TypeScript projects.
|
|
9
17
|
|
|
10
18
|
## Installation
|
|
11
19
|
|
|
20
|
+
### npm
|
|
21
|
+
|
|
12
22
|
```bash
|
|
13
23
|
npm install express-version-api
|
|
14
24
|
```
|
|
15
25
|
|
|
26
|
+
### JSR
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
deno add jsr:@braian-quintian/express-version-api
|
|
30
|
+
```
|
|
31
|
+
|
|
16
32
|
Requirements:
|
|
17
33
|
|
|
18
34
|
- Node.js >= 18
|
|
@@ -26,71 +42,82 @@ import { versioningMiddleware } from 'express-version-api';
|
|
|
26
42
|
|
|
27
43
|
const app = express();
|
|
28
44
|
|
|
29
|
-
app.
|
|
30
|
-
'/api',
|
|
45
|
+
app.get(
|
|
46
|
+
'/api/users',
|
|
31
47
|
versioningMiddleware({
|
|
32
|
-
'^1': (_req, res) => {
|
|
33
|
-
|
|
34
|
-
},
|
|
35
|
-
'^2': (_req, res) => {
|
|
36
|
-
res.json({ version: '2.x' });
|
|
37
|
-
},
|
|
38
|
-
'3.0.0': (_req, res) => {
|
|
39
|
-
res.json({ version: '3.0.0' });
|
|
40
|
-
},
|
|
48
|
+
'^1': (_req, res) => res.json({ version: '1.x', users: [] }),
|
|
49
|
+
'^2': (_req, res) => res.json({ version: '2.x', users: [], meta: { total: 0 } }),
|
|
50
|
+
'3.0.0': (_req, res) => res.json({ version: '3.0.0', users: [], paging: null }),
|
|
41
51
|
})
|
|
42
52
|
);
|
|
53
|
+
|
|
54
|
+
app.use((error, _req, res, _next) => {
|
|
55
|
+
res.status(500).json({ error: error.message });
|
|
56
|
+
});
|
|
43
57
|
```
|
|
44
58
|
|
|
45
59
|
Request examples:
|
|
46
60
|
|
|
47
61
|
```bash
|
|
48
|
-
curl -H "Accept-Version: 1.2.0" http://localhost:3000/api
|
|
49
|
-
curl -H "Accept-Version: 2.5.1" http://localhost:3000/api
|
|
50
|
-
curl -H "Accept-Version: 3.0.0" http://localhost:3000/api
|
|
62
|
+
curl -H "Accept-Version: 1.2.0" http://localhost:3000/api/users
|
|
63
|
+
curl -H "Accept-Version: 2.5.1" http://localhost:3000/api/users
|
|
64
|
+
curl -H "Accept-Version: 3.0.0" http://localhost:3000/api/users
|
|
51
65
|
```
|
|
52
66
|
|
|
53
67
|
## Import Modes
|
|
54
68
|
|
|
55
|
-
ESM:
|
|
69
|
+
ESM (default + named):
|
|
56
70
|
|
|
57
71
|
```ts
|
|
58
72
|
import versioningMiddleware, { parseVersion } from 'express-version-api';
|
|
59
73
|
```
|
|
60
74
|
|
|
61
|
-
CommonJS:
|
|
75
|
+
CommonJS (named only):
|
|
62
76
|
|
|
63
77
|
```js
|
|
64
78
|
const { versioningMiddleware, parseVersion } = require('express-version-api');
|
|
65
79
|
```
|
|
66
80
|
|
|
67
|
-
## Matching Rules
|
|
81
|
+
## Version Matching Rules
|
|
68
82
|
|
|
69
83
|
Supported handler keys:
|
|
70
84
|
|
|
71
85
|
- Exact: `1.2.3`
|
|
72
|
-
- Caret: `^1.2.3`
|
|
73
|
-
- Tilde: `~1.2.3`
|
|
86
|
+
- Caret: `^1`, `^1.2`, `^1.2.3`
|
|
87
|
+
- Tilde: `~1.2`, `~1.2.3`
|
|
74
88
|
|
|
75
|
-
|
|
89
|
+
Matching priority when multiple handlers match:
|
|
76
90
|
|
|
77
91
|
1. Exact
|
|
78
92
|
2. Tilde
|
|
79
93
|
3. Caret
|
|
80
94
|
|
|
81
|
-
|
|
95
|
+
Semantics:
|
|
96
|
+
|
|
97
|
+
- Exact: must match the same `major.minor.patch`.
|
|
98
|
+
- Tilde (`~`): same major and minor, patch must be `>=` requested patch.
|
|
99
|
+
- Caret (`^`): semver-compatible range.
|
|
100
|
+
- Caret with `0.x` follows strict semver-compatible behavior.
|
|
82
101
|
|
|
83
|
-
|
|
84
|
-
- Versions like `1`, `1.2`, and `1.2.3` are accepted.
|
|
102
|
+
Examples:
|
|
85
103
|
|
|
86
|
-
|
|
104
|
+
- `^1.2.3` matches `1.2.3`, `1.3.0`, `1.9.9`, but not `2.0.0`.
|
|
105
|
+
- `^0.2.3` matches `0.2.3` to `0.2.x`, but not `0.3.0`.
|
|
106
|
+
- `~2.1.4` matches `2.1.4` to `2.1.x`, but not `2.2.0`.
|
|
87
107
|
|
|
88
|
-
|
|
108
|
+
## How Version Extraction Works
|
|
109
|
+
|
|
110
|
+
The middleware resolves version in this order:
|
|
111
|
+
|
|
112
|
+
1. `req.version` if already set by upstream middleware (source = `custom`)
|
|
113
|
+
2. Configured extraction sources in order (`extraction.sources`)
|
|
114
|
+
|
|
115
|
+
Default source order:
|
|
89
116
|
|
|
90
117
|
1. Header: `accept-version`
|
|
91
118
|
2. Query: `v`
|
|
92
119
|
|
|
93
|
-
You can configure `header`, `query`, `path`,
|
|
120
|
+
You can configure `header`, `query`, `path`, and `custom` extractors.
|
|
94
121
|
|
|
95
122
|
```ts
|
|
96
123
|
versioningMiddleware(
|
|
@@ -110,57 +137,26 @@ versioningMiddleware(
|
|
|
110
137
|
);
|
|
111
138
|
```
|
|
112
139
|
|
|
113
|
-
##
|
|
140
|
+
## Fallback Strategies
|
|
114
141
|
|
|
115
|
-
|
|
142
|
+
Fallback is used when no handler matches, and also when version is missing with `requireVersion: false`.
|
|
116
143
|
|
|
117
|
-
- `
|
|
118
|
-
- `
|
|
119
|
-
- `
|
|
120
|
-
- `validateHandlers: true`
|
|
121
|
-
- `errorResponse.missingVersionStatus: 422`
|
|
122
|
-
- `errorResponse.versionNotFoundStatus: 422`
|
|
123
|
-
- `errorResponse.missingVersionMessage: 'API version is required'`
|
|
144
|
+
- `none`: respond with `VERSION_NOT_FOUND`.
|
|
145
|
+
- `latest`: execute the handler with the highest available version.
|
|
146
|
+
- `default`: execute `defaultHandler` if provided, otherwise fallback to `latest`.
|
|
124
147
|
|
|
125
148
|
```ts
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
custom?: (req: Request) => string | undefined;
|
|
133
|
-
};
|
|
134
|
-
requireVersion?: boolean;
|
|
135
|
-
fallbackStrategy?: 'latest' | 'none' | 'default';
|
|
136
|
-
defaultHandler?: RequestHandler;
|
|
137
|
-
validateHandlers?: boolean;
|
|
138
|
-
attachVersionInfo?: boolean;
|
|
139
|
-
errorResponse?: {
|
|
140
|
-
missingVersionStatus?: number;
|
|
141
|
-
versionNotFoundStatus?: number;
|
|
142
|
-
missingVersionMessage?: string;
|
|
143
|
-
versionNotFoundMessage?: string | ((version: string) => string);
|
|
144
|
-
includeRequestedVersion?: boolean;
|
|
145
|
-
onError?: (
|
|
146
|
-
error: VersioningError,
|
|
147
|
-
req: Request,
|
|
148
|
-
res: Response,
|
|
149
|
-
next: NextFunction
|
|
150
|
-
) => boolean | undefined;
|
|
151
|
-
};
|
|
152
|
-
}
|
|
149
|
+
versioningMiddleware(handlers, {
|
|
150
|
+
fallbackStrategy: 'default',
|
|
151
|
+
defaultHandler: (_req, res) => {
|
|
152
|
+
res.status(200).json({ fallback: true });
|
|
153
|
+
},
|
|
154
|
+
});
|
|
153
155
|
```
|
|
154
156
|
|
|
155
|
-
## Fallback Strategies
|
|
156
|
-
|
|
157
|
-
- `none`: return `VERSION_NOT_FOUND` error.
|
|
158
|
-
- `latest`: execute the highest available version handler.
|
|
159
|
-
- `default`: execute `defaultHandler` when provided; otherwise falls back to `latest`.
|
|
160
|
-
|
|
161
157
|
## Error Handling
|
|
162
158
|
|
|
163
|
-
Error codes:
|
|
159
|
+
Error codes emitted by the middleware:
|
|
164
160
|
|
|
165
161
|
- `MISSING_VERSION`
|
|
166
162
|
- `INVALID_VERSION_FORMAT`
|
|
@@ -168,7 +164,13 @@ Error codes:
|
|
|
168
164
|
- `INVALID_CONFIGURATION`
|
|
169
165
|
- `INVALID_HANDLER`
|
|
170
166
|
|
|
171
|
-
Default
|
|
167
|
+
Default status codes:
|
|
168
|
+
|
|
169
|
+
- Missing version: `422`
|
|
170
|
+
- Version not found: `422`
|
|
171
|
+
- Invalid version format: `400`
|
|
172
|
+
|
|
173
|
+
Default response shape:
|
|
172
174
|
|
|
173
175
|
```json
|
|
174
176
|
{
|
|
@@ -179,9 +181,28 @@ Default error response shape:
|
|
|
179
181
|
}
|
|
180
182
|
```
|
|
181
183
|
|
|
182
|
-
|
|
184
|
+
Configure custom messages/statuses and override handling via `onError`:
|
|
183
185
|
|
|
184
|
-
|
|
186
|
+
```ts
|
|
187
|
+
versioningMiddleware(handlers, {
|
|
188
|
+
errorResponse: {
|
|
189
|
+
missingVersionStatus: 400,
|
|
190
|
+
missingVersionMessage: 'Version header is required',
|
|
191
|
+
versionNotFoundMessage: (version) => `Version ${version} is not supported`,
|
|
192
|
+
onError: (error, _req, res) => {
|
|
193
|
+
if (error.code === 'INVALID_VERSION_FORMAT') {
|
|
194
|
+
res.status(400).json({ code: error.code, detail: error.message });
|
|
195
|
+
return true;
|
|
196
|
+
}
|
|
197
|
+
return false;
|
|
198
|
+
},
|
|
199
|
+
},
|
|
200
|
+
});
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
## Request Metadata (`req.versionInfo`)
|
|
204
|
+
|
|
205
|
+
When `attachVersionInfo` is `true`, the middleware adds:
|
|
185
206
|
|
|
186
207
|
```ts
|
|
187
208
|
{
|
|
@@ -191,11 +212,57 @@ When `attachVersionInfo` is enabled, the middleware sets `req.versionInfo`:
|
|
|
191
212
|
}
|
|
192
213
|
```
|
|
193
214
|
|
|
194
|
-
|
|
215
|
+
Notes:
|
|
216
|
+
|
|
217
|
+
- `source` preserves the real extraction source, including fallback scenarios.
|
|
218
|
+
- When no version was provided and fallback is used, `versionInfo` is not attached because `requested` is undefined.
|
|
219
|
+
|
|
220
|
+
## Runtime Defaults
|
|
195
221
|
|
|
196
|
-
|
|
222
|
+
```ts
|
|
223
|
+
{
|
|
224
|
+
extraction: {
|
|
225
|
+
sources: ['header', 'query'],
|
|
226
|
+
header: { name: 'accept-version' },
|
|
227
|
+
query: { name: 'v' },
|
|
228
|
+
path: { pattern: /\/v(\d+(?:\.\d+)?(?:\.\d+)?)\// },
|
|
229
|
+
custom: undefined
|
|
230
|
+
},
|
|
231
|
+
errorResponse: {
|
|
232
|
+
missingVersionStatus: 422,
|
|
233
|
+
versionNotFoundStatus: 422,
|
|
234
|
+
missingVersionMessage: 'API version is required',
|
|
235
|
+
versionNotFoundMessage: 'No handler found for the requested API version',
|
|
236
|
+
includeRequestedVersion: true,
|
|
237
|
+
onError: undefined
|
|
238
|
+
},
|
|
239
|
+
fallbackStrategy: 'default',
|
|
240
|
+
defaultHandler: undefined,
|
|
241
|
+
validateHandlers: true,
|
|
242
|
+
attachVersionInfo: true,
|
|
243
|
+
requireVersion: true
|
|
244
|
+
}
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
## Public API
|
|
248
|
+
|
|
249
|
+
Main middleware:
|
|
197
250
|
|
|
198
251
|
- `versioningMiddleware`
|
|
252
|
+
|
|
253
|
+
Error helpers:
|
|
254
|
+
|
|
255
|
+
- `VersioningError`
|
|
256
|
+
- `createMissingVersionError`
|
|
257
|
+
- `createVersionNotFoundError`
|
|
258
|
+
- `createInvalidVersionFormatError`
|
|
259
|
+
- `createInvalidHandlerError`
|
|
260
|
+
- `createInvalidConfigurationError`
|
|
261
|
+
- `isVersioningError`
|
|
262
|
+
- `hasErrorCode`
|
|
263
|
+
|
|
264
|
+
Version utilities:
|
|
265
|
+
|
|
199
266
|
- `parseVersion`
|
|
200
267
|
- `parseVersionRange`
|
|
201
268
|
- `versionSatisfies`
|
|
@@ -204,13 +271,15 @@ Main exports:
|
|
|
204
271
|
- `isValidVersion`
|
|
205
272
|
- `isValidVersionRange`
|
|
206
273
|
- `normalizeVersion`
|
|
207
|
-
|
|
274
|
+
|
|
275
|
+
Config export:
|
|
276
|
+
|
|
208
277
|
- `DEFAULT_CONFIG`
|
|
209
278
|
|
|
210
|
-
## Breaking Changes (v2
|
|
279
|
+
## Breaking Changes (v2)
|
|
211
280
|
|
|
212
281
|
- Removed legacy `createVersionMiddleware` API.
|
|
213
|
-
- CommonJS
|
|
282
|
+
- CommonJS default export was removed; CJS must use named imports.
|
|
214
283
|
|
|
215
284
|
## Development
|
|
216
285
|
|
|
@@ -219,6 +288,16 @@ npm install
|
|
|
219
288
|
npm run validate
|
|
220
289
|
```
|
|
221
290
|
|
|
291
|
+
Main scripts:
|
|
292
|
+
|
|
293
|
+
- `npm run typecheck`
|
|
294
|
+
- `npm run lint`
|
|
295
|
+
- `npm run format:check`
|
|
296
|
+
- `npm run test`
|
|
297
|
+
- `npm run test:coverage`
|
|
298
|
+
- `npm run build`
|
|
299
|
+
- `npm run test:types`
|
|
300
|
+
|
|
222
301
|
## License
|
|
223
302
|
|
|
224
303
|
MIT
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "express-version-api",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.5",
|
|
4
4
|
"description": "Middleware for versioning routes/APIs in Express.js using semantic versioning like ^1.0 or ~1.2.",
|
|
5
5
|
"author": "Braian Quintian <bquintian.developer@gmail.com>",
|
|
6
6
|
"license": "MIT",
|