@rodit/rodit-auth-be 9.11.14

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.
@@ -0,0 +1,142 @@
1
+ /**
2
+ * API Versioning Middleware
3
+ *
4
+ * This middleware handles API versioning through HTTP headers.
5
+ * It supports both client request versioning and server response versioning.
6
+ *
7
+ * Copyright (c) 2026 Discernible IO. All rights reserved.
8
+ */
9
+
10
+ const logger = require('../../services/logger');
11
+ const config = require('../../services/configsdk');
12
+ const { sendError } = require('../../services/error-response');
13
+
14
+
15
+
16
+ /**
17
+ * Parse version from header value
18
+ * @param {string} headerValue - Value from Accept or X-API-Version header
19
+ * @returns {string} Parsed version or default version
20
+ */
21
+ function parseVersionFromHeader(headerValue) {
22
+ if (!headerValue) return config.get('API_VERSION');
23
+
24
+ // Handle Accept header format: application/vnd.company.vX+json
25
+ const vendorMatch = headerValue.match(/application\/vnd\.rodit\.v([0-9.]+)\+json/i);
26
+ if (vendorMatch && vendorMatch[1]) {
27
+ return vendorMatch[1];
28
+ }
29
+
30
+ // Handle X-API-Version header format: X.Y.Z
31
+ const versionMatch = headerValue.match(/([0-9]+\.[0-9]+\.[0-9]+)/);
32
+ if (versionMatch && versionMatch[1]) {
33
+ return versionMatch[1];
34
+ }
35
+
36
+ return config.get('API_VERSION');
37
+ }
38
+
39
+ /**
40
+ * Check if requested version is supported
41
+ * @param {string} version - Requested version
42
+ * @returns {boolean} True if version is supported
43
+ */
44
+ function isVersionSupported(version) {
45
+ return AVAILABLE_VERSIONS.includes(version);
46
+ }
47
+
48
+ /**
49
+ * Check if version is deprecated
50
+ * @param {string} version - API version
51
+ * @returns {boolean} True if version is deprecated
52
+ */
53
+ function isVersionDeprecated(version) {
54
+ return DEPRECATED_VERSIONS.includes(version);
55
+ }
56
+
57
+ /**
58
+ * Get major version number from version string
59
+ * @param {string} version - Version string (e.g., "1.2.3")
60
+ * @returns {number} Major version number
61
+ */
62
+ function getMajorVersion(version) {
63
+ const parts = version.split('.');
64
+ return parseInt(parts[0], 10);
65
+ }
66
+
67
+ /**
68
+ * Middleware to handle API versioning
69
+ * @param {Object} versioning - Configuration versioning
70
+ * @param {boolean} [versioning.strict=false] - If true, reject requests with unsupported versions
71
+ * @returns {Function} Express middleware
72
+ */
73
+ function versioningMiddleware(versioning = {}) {
74
+ const strict = versioning.strict || false;
75
+
76
+ return (req, res, next) => {
77
+ const requestId = req.requestId || req.headers['x-request-id'] || 'unknown';
78
+ const logContext = { component: 'versioningMiddleware', requestId };
79
+ logger.infoWithContext('API versioning middleware engaged', {
80
+ ...logContext,
81
+ result: 'call',
82
+ reason: 'Versioning middleware called'
83
+ });
84
+
85
+ // Check for version in headers (multiple possible formats)
86
+ const acceptHeader = req.headers['accept'];
87
+ const versionHeader = req.headers['x-api-version'];
88
+
89
+ // Parse version from headers
90
+ let requestedVersion = parseVersionFromHeader(versionHeader || acceptHeader);
91
+
92
+ // Check if version is supported
93
+ if (!isVersionSupported(requestedVersion)) {
94
+ logger.warnWithContext('Unsupported API version requested', {
95
+ ...logContext,
96
+ version: requestedVersion,
97
+ result: 'failure',
98
+ reason: `API version ${requestedVersion} is not supported.`
99
+ });
100
+
101
+ if (strict) {
102
+ return sendError(res, {
103
+ statusCode: 400,
104
+ requestId,
105
+ code: 'UNSUPPORTED_VERSION',
106
+ message: `API version ${requestedVersion} is not supported. Supported versions: ${AVAILABLE_VERSIONS.join(', ')}`,
107
+ details: { supportedVersions: AVAILABLE_VERSIONS }
108
+ });
109
+ }
110
+ requestedVersion = config.get('API_VERSION');
111
+ }
112
+
113
+ // Add version info to request object for use in route handlers
114
+ req.apiVersion = requestedVersion;
115
+ req.apiMajorVersion = getMajorVersion(requestedVersion);
116
+
117
+ // Add deprecation warning header if applicable
118
+ if (isVersionDeprecated(requestedVersion)) {
119
+ res.setHeader('Warning', `299 - "Deprecated API version ${requestedVersion}. Please upgrade to a newer version."`);
120
+ res.setHeader('X-API-Deprecated', 'true');
121
+ res.setHeader('X-API-Deprecated-Message', `Version ${requestedVersion} is deprecated and will be removed in the future.`);
122
+ }
123
+
124
+ // Set response version header
125
+ res.setHeader('X-API-Version', requestedVersion);
126
+
127
+ logger.infoWithContext('API request using version', {
128
+ ...logContext,
129
+ version: requestedVersion,
130
+ result: 'success',
131
+ reason: `API request using version ${requestedVersion}`
132
+ });
133
+ next();
134
+ };
135
+ }
136
+
137
+ module.exports = {
138
+ versioningMiddleware,
139
+ parseVersionFromHeader,
140
+ isVersionSupported,
141
+ isVersionDeprecated
142
+ };