0
# Specification Extensions
1
2
Support for OpenAPI specification extensions (`x-*` properties) with validation and management utilities.
3
4
## Capabilities
5
6
### Extension Type Definitions
7
8
Core types for working with OpenAPI specification extensions.
9
10
```typescript { .api }
11
/**
12
* Extension name pattern - must start with 'x-'
13
*/
14
type IExtensionName = `x-${string}`;
15
16
/**
17
* Extension value type - can be any value
18
*/
19
type IExtensionType = any;
20
21
/**
22
* Interface for objects supporting specification extensions
23
*/
24
interface ISpecificationExtension {
25
[extensionName: IExtensionName]: IExtensionType;
26
}
27
```
28
29
### SpecificationExtension Class
30
31
Implementation class for managing OpenAPI specification extensions.
32
33
```typescript { .api }
34
/**
35
* Specification extension management class
36
*/
37
class SpecificationExtension implements ISpecificationExtension {
38
[extensionName: IExtensionName]: any;
39
40
/**
41
* Validate if an extension name follows the x- pattern
42
* @param extensionName - Extension name to validate
43
* @returns True if extension name is valid (starts with 'x-')
44
*/
45
static isValidExtension(extensionName: string): boolean;
46
47
/**
48
* Get an extension value by name
49
* @param extensionName - Extension name (must start with 'x-')
50
* @returns Extension value or null if not found
51
* @throws Error if extension name is invalid
52
*/
53
getExtension(extensionName: string): any;
54
55
/**
56
* Add an extension with validation
57
* @param extensionName - Extension name (must start with 'x-')
58
* @param payload - Extension value
59
* @throws Error if extension name is invalid
60
*/
61
addExtension(extensionName: string, payload: any): void;
62
63
/**
64
* List all extension names on this object
65
* @returns Array of extension names
66
*/
67
listExtensions(): string[];
68
}
69
```
70
71
**Usage Examples:**
72
73
```typescript
74
import { SpecificationExtension } from "openapi3-ts";
75
76
// Create extension manager
77
const extensions = new SpecificationExtension();
78
79
// Add extensions
80
extensions.addExtension("x-custom-field", "custom value");
81
extensions.addExtension("x-rate-limit", { requests: 100, window: "1m" });
82
extensions.addExtension("x-internal-id", 12345);
83
84
// Get extension values
85
const customField = extensions.getExtension("x-custom-field");
86
console.log(customField); // "custom value"
87
88
const rateLimit = extensions.getExtension("x-rate-limit");
89
console.log(rateLimit); // { requests: 100, window: "1m" }
90
91
// List all extensions
92
const extensionNames = extensions.listExtensions();
93
console.log(extensionNames); // ["x-custom-field", "x-rate-limit", "x-internal-id"]
94
95
// Validate extension names
96
console.log(SpecificationExtension.isValidExtension("x-valid")); // true
97
console.log(SpecificationExtension.isValidExtension("invalid")); // false
98
99
// Error handling
100
try {
101
extensions.addExtension("invalid-name", "value");
102
} catch (error) {
103
console.error(error.message); // "Invalid specification extension..."
104
}
105
```
106
107
### Utility Functions
108
109
Helper functions for working with extensions on any OpenAPI object.
110
111
```typescript { .api }
112
/**
113
* Get an extension value from any object supporting extensions
114
* @param obj - Object with potential extensions
115
* @param extensionName - Extension name (must start with 'x-')
116
* @returns Extension value or undefined
117
*/
118
function getExtension(
119
obj: ISpecificationExtension | undefined,
120
extensionName: string
121
): any;
122
123
/**
124
* Add an extension to any object supporting extensions
125
* @param obj - Object to add extension to
126
* @param extensionName - Extension name (must start with 'x-')
127
* @param extension - Extension value
128
*/
129
function addExtension(
130
obj: ISpecificationExtension | undefined,
131
extensionName: string,
132
extension: any
133
): void;
134
```
135
136
**Usage Examples:**
137
138
```typescript
139
import { oas30, getExtension, addExtension } from "openapi3-ts";
140
141
// Create OpenAPI objects
142
const schema: oas30.SchemaObject = {
143
type: "object",
144
properties: {
145
id: { type: "integer" }
146
}
147
};
148
149
const operation: oas30.OperationObject = {
150
summary: "Get item",
151
responses: {
152
"200": { description: "Success" }
153
}
154
};
155
156
// Add extensions using utility functions
157
addExtension(schema, "x-database-table", "items");
158
addExtension(schema, "x-validation-level", "strict");
159
160
addExtension(operation, "x-rate-limit", 1000);
161
addExtension(operation, "x-cached", true);
162
163
// Get extensions using utility functions
164
const tableName = getExtension(schema, "x-database-table");
165
console.log(tableName); // "items"
166
167
const rateLimit = getExtension(operation, "x-rate-limit");
168
console.log(rateLimit); // 1000
169
170
// Extensions are accessible as properties too
171
console.log(schema["x-validation-level"]); // "strict"
172
console.log(operation["x-cached"]); // true
173
```
174
175
## Extension Patterns and Examples
176
177
### Common Extension Patterns
178
179
```typescript
180
import { oas30 } from "openapi3-ts";
181
182
// Vendor-specific extensions
183
const spec = oas30.OpenApiBuilder.create()
184
.addTitle("API with Extensions")
185
.addVersion("1.0.0")
186
.getSpec();
187
188
// Add vendor extensions to the root document
189
spec["x-amazon-apigateway-cors"] = {
190
allowOrigins: ["*"],
191
allowMethods: ["GET", "POST"],
192
allowHeaders: ["Content-Type", "Authorization"]
193
};
194
195
spec["x-swagger-ui"] = {
196
theme: "dark",
197
displayRequestDuration: true
198
};
199
200
// Schema-level extensions for code generation
201
const userSchema: oas30.SchemaObject = {
202
type: "object",
203
required: ["id", "name"],
204
properties: {
205
id: { type: "integer", format: "int64" },
206
name: { type: "string" },
207
email: { type: "string", format: "email" }
208
}
209
};
210
211
// Add code generation hints
212
userSchema["x-go-type"] = "User";
213
userSchema["x-java-class"] = "com.example.User";
214
userSchema["x-database-table"] = "users";
215
userSchema["x-tags"] = ["entity", "user"];
216
217
// Operation-level extensions for infrastructure
218
const getUserOperation: oas30.OperationObject = {
219
summary: "Get user by ID",
220
parameters: [
221
{
222
name: "id",
223
in: "path",
224
required: true,
225
schema: { type: "integer" }
226
}
227
],
228
responses: {
229
"200": {
230
description: "User found",
231
content: {
232
"application/json": {
233
schema: { $ref: "#/components/schemas/User" }
234
}
235
}
236
}
237
}
238
};
239
240
// Add infrastructure extensions
241
getUserOperation["x-rate-limit"] = { requests: 100, window: "1m" };
242
getUserOperation["x-cache-ttl"] = 300; // 5 minutes
243
getUserOperation["x-auth-required"] = true;
244
getUserOperation["x-permissions"] = ["user:read"];
245
```
246
247
### Extension Validation and Management
248
249
```typescript
250
import { SpecificationExtension, ISpecificationExtension } from "openapi3-ts";
251
252
// Helper class for managing typed extensions
253
class ExtensionManager {
254
private extensions: ISpecificationExtension = {};
255
256
addRateLimit(requests: number, window: string): void {
257
this.extensions["x-rate-limit"] = { requests, window };
258
}
259
260
addCacheSettings(ttl: number, strategy: string): void {
261
this.extensions["x-cache"] = { ttl, strategy };
262
}
263
264
addVendorConfig(vendor: string, config: object): void {
265
const extensionName = `x-${vendor}-config` as any;
266
if (SpecificationExtension.isValidExtension(extensionName)) {
267
this.extensions[extensionName] = config;
268
}
269
}
270
271
applyTo(target: ISpecificationExtension): void {
272
Object.keys(this.extensions).forEach(key => {
273
if (SpecificationExtension.isValidExtension(key)) {
274
target[key as any] = this.extensions[key as any];
275
}
276
});
277
}
278
279
getExtensions(): ISpecificationExtension {
280
return { ...this.extensions };
281
}
282
}
283
284
// Usage
285
const extManager = new ExtensionManager();
286
extManager.addRateLimit(1000, "1h");
287
extManager.addCacheSettings(600, "lru");
288
extManager.addVendorConfig("aws", {
289
region: "us-east-1",
290
timeout: 30000
291
});
292
293
// Apply to OpenAPI objects
294
const operation: oas30.OperationObject = {
295
summary: "Test operation",
296
responses: { "200": { description: "Success" } }
297
};
298
299
extManager.applyTo(operation);
300
console.log(operation["x-rate-limit"]); // { requests: 1000, window: "1h" }
301
console.log(operation["x-aws-config"]); // { region: "us-east-1", timeout: 30000 }
302
```
303
304
### Extension Integration with Builders
305
306
```typescript
307
import { oas30, SpecificationExtension } from "openapi3-ts";
308
309
// Extend builder with extension support
310
class ExtendedOpenApiBuilder extends oas30.OpenApiBuilder {
311
addExtension(extensionName: string, value: any): ExtendedOpenApiBuilder {
312
if (SpecificationExtension.isValidExtension(extensionName)) {
313
this.rootDoc[extensionName as any] = value;
314
} else {
315
throw new Error(`Invalid extension name: ${extensionName}`);
316
}
317
return this;
318
}
319
320
addSchemaWithExtensions(
321
name: string,
322
schema: oas30.SchemaObject,
323
extensions: { [key: string]: any }
324
): ExtendedOpenApiBuilder {
325
// Add extensions to schema
326
Object.keys(extensions).forEach(key => {
327
if (SpecificationExtension.isValidExtension(key)) {
328
(schema as any)[key] = extensions[key];
329
}
330
});
331
332
return this.addSchema(name, schema) as ExtendedOpenApiBuilder;
333
}
334
335
addOperationWithExtensions(
336
path: string,
337
method: string,
338
operation: oas30.OperationObject,
339
extensions: { [key: string]: any }
340
): ExtendedOpenApiBuilder {
341
// Add extensions to operation
342
Object.keys(extensions).forEach(key => {
343
if (SpecificationExtension.isValidExtension(key)) {
344
(operation as any)[key] = extensions[key];
345
}
346
});
347
348
const pathItem: oas30.PathItemObject = {
349
[method]: operation
350
};
351
352
return this.addPath(path, pathItem) as ExtendedOpenApiBuilder;
353
}
354
}
355
356
// Usage
357
const spec = new ExtendedOpenApiBuilder()
358
.addTitle("Extended API")
359
.addVersion("1.0.0")
360
.addExtension("x-api-id", "api-12345")
361
.addExtension("x-build-info", {
362
version: "1.2.3",
363
buildTime: new Date().toISOString(),
364
gitCommit: "abc123"
365
})
366
.addSchemaWithExtensions("User", {
367
type: "object",
368
properties: {
369
id: { type: "integer" },
370
name: { type: "string" }
371
}
372
}, {
373
"x-database-table": "users",
374
"x-java-class": "com.example.User"
375
})
376
.addOperationWithExtensions("/users", "get", {
377
summary: "List users",
378
responses: {
379
"200": { description: "Success" }
380
}
381
}, {
382
"x-rate-limit": { requests: 100, window: "1m" },
383
"x-cache-ttl": 300
384
})
385
.getSpec();
386
387
console.log(spec["x-api-id"]); // "api-12345"
388
console.log(spec.components?.schemas?.User?.["x-database-table"]); // "users"
389
```
390
391
## Best Practices
392
393
### Extension Naming Conventions
394
395
```typescript
396
// Good extension names
397
const goodExtensions = [
398
"x-internal-id", // kebab-case
399
"x-rate-limit", // descriptive
400
"x-vendor-config", // vendor prefix
401
"x-code-gen-options", // purpose clear
402
];
403
404
// Poor extension names
405
const poorExtensions = [
406
"x-data", // too generic
407
"x-temp", // unclear purpose
408
"x-customField", // camelCase (prefer kebab)
409
"x-123", // starts with number
410
];
411
412
// Validation helper
413
function isGoodExtensionName(name: string): boolean {
414
return SpecificationExtension.isValidExtension(name) &&
415
name.length > 2 &&
416
/^x-[a-z][a-z0-9-]*$/.test(name);
417
}
418
```
419
420
### Type-Safe Extension Handling
421
422
```typescript
423
import { ISpecificationExtension } from "openapi3-ts";
424
425
// Define typed extension interfaces
426
interface RateLimitExtension {
427
"x-rate-limit": {
428
requests: number;
429
window: string;
430
};
431
}
432
433
interface CacheExtension {
434
"x-cache-ttl": number;
435
}
436
437
// Utility types for extension combinations
438
type WithRateLimit<T> = T & RateLimitExtension;
439
type WithCache<T> = T & CacheExtension;
440
type WithBoth<T> = T & RateLimitExtension & CacheExtension;
441
442
// Type-safe extension helpers
443
function addRateLimit<T extends ISpecificationExtension>(
444
obj: T,
445
requests: number,
446
window: string
447
): WithRateLimit<T> {
448
(obj as any)["x-rate-limit"] = { requests, window };
449
return obj as WithRateLimit<T>;
450
}
451
452
function addCache<T extends ISpecificationExtension>(
453
obj: T,
454
ttl: number
455
): WithCache<T> {
456
(obj as any)["x-cache-ttl"] = ttl;
457
return obj as WithCache<T>;
458
}
459
460
// Usage with type safety
461
import { oas30 } from "openapi3-ts";
462
463
let operation: oas30.OperationObject = {
464
summary: "Get user",
465
responses: { "200": { description: "Success" } }
466
};
467
468
// Chain extensions with type safety
469
operation = addCache(addRateLimit(operation, 100, "1m"), 300);
470
471
// TypeScript knows about the extensions
472
console.log(operation["x-rate-limit"].requests); // 100
473
console.log(operation["x-cache-ttl"]); // 300
474
```