@loopback/openapi-v3 1.10.1 → 1.12.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.
- package/CHANGELOG.md +40 -0
- package/dist/controller-spec.js +62 -31
- package/dist/controller-spec.js.map +1 -1
- package/dist/decorators/api.decorator.js +2 -2
- package/dist/decorators/api.decorator.js.map +1 -1
- package/dist/decorators/operation.decorator.js +2 -2
- package/dist/decorators/operation.decorator.js.map +1 -1
- package/dist/decorators/parameter.decorator.js +5 -4
- package/dist/decorators/parameter.decorator.js.map +1 -1
- package/dist/decorators/request-body.decorator.js +12 -8
- package/dist/decorators/request-body.decorator.js.map +1 -1
- package/dist/enhancers/index.d.ts +3 -0
- package/dist/enhancers/index.js +13 -0
- package/dist/enhancers/index.js.map +1 -0
- package/dist/enhancers/keys.d.ts +6 -0
- package/dist/enhancers/keys.js +12 -0
- package/dist/enhancers/keys.js.map +1 -0
- package/dist/enhancers/spec-enhancer.service.d.ts +73 -0
- package/dist/enhancers/spec-enhancer.service.js +135 -0
- package/dist/enhancers/spec-enhancer.service.js.map +1 -0
- package/dist/enhancers/types.d.ts +18 -0
- package/dist/enhancers/types.js +20 -0
- package/dist/enhancers/types.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/json-to-schema.js +16 -11
- package/dist/json-to-schema.js.map +1 -1
- package/dist/keys.d.ts +1 -1
- package/dist/keys.js +6 -10
- package/dist/keys.js.map +1 -1
- package/package.json +12 -11
- package/src/controller-spec.ts +53 -21
- package/src/decorators/api.decorator.ts +1 -1
- package/src/decorators/operation.decorator.ts +1 -1
- package/src/decorators/parameter.decorator.ts +2 -2
- package/src/decorators/request-body.decorator.ts +4 -4
- package/src/enhancers/index.ts +8 -0
- package/src/enhancers/keys.ts +14 -0
- package/src/enhancers/spec-enhancer.service.ts +121 -0
- package/src/enhancers/types.ts +30 -0
- package/src/index.ts +1 -0
- package/src/json-to-schema.ts +14 -8
- package/src/keys.ts +1 -6
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
// Copyright IBM Corp. 2019. All Rights Reserved.
|
|
2
|
+
// Node module: @loopback/openapi-v3
|
|
3
|
+
// This file is licensed under the MIT License.
|
|
4
|
+
// License text available at https://opensource.org/licenses/MIT
|
|
5
|
+
|
|
6
|
+
import {config, extensionPoint, extensions, Getter} from '@loopback/core';
|
|
7
|
+
import debugModule from 'debug';
|
|
8
|
+
import * as _ from 'lodash';
|
|
9
|
+
import {inspect} from 'util';
|
|
10
|
+
import {OpenApiSpec} from '../types';
|
|
11
|
+
import {OASEnhancer, OAS_ENHANCER_EXTENSION_POINT_NAME} from './types';
|
|
12
|
+
const jsonmergepatch = require('json-merge-patch');
|
|
13
|
+
|
|
14
|
+
const debug = debugModule('loopback:openapi:spec-enhancer');
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Options for the OpenAPI Spec enhancer extension point
|
|
18
|
+
*/
|
|
19
|
+
export interface OASEnhancerServiceOptions {
|
|
20
|
+
// no-op
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* An extension point for OpenAPI Spec enhancement
|
|
25
|
+
* This service is used for enhancing an OpenAPI spec by loading and applying one or more
|
|
26
|
+
* registered enhancers.
|
|
27
|
+
*
|
|
28
|
+
* A typical use of it would be generating the OpenAPI spec for the endpoints on a server
|
|
29
|
+
* in the `@loopback/rest` module.
|
|
30
|
+
*/
|
|
31
|
+
@extensionPoint(OAS_ENHANCER_EXTENSION_POINT_NAME)
|
|
32
|
+
export class OASEnhancerService {
|
|
33
|
+
constructor(
|
|
34
|
+
/**
|
|
35
|
+
* Inject a getter function to fetch spec enhancers
|
|
36
|
+
*/
|
|
37
|
+
@extensions()
|
|
38
|
+
private getEnhancers: Getter<OASEnhancer[]>,
|
|
39
|
+
/**
|
|
40
|
+
* An extension point should be able to receive its options via dependency
|
|
41
|
+
* injection.
|
|
42
|
+
*/
|
|
43
|
+
@config()
|
|
44
|
+
public readonly options?: OASEnhancerServiceOptions,
|
|
45
|
+
) {}
|
|
46
|
+
|
|
47
|
+
private _spec: OpenApiSpec = {
|
|
48
|
+
openapi: '3.0.0',
|
|
49
|
+
info: {
|
|
50
|
+
title: 'LoopBack Application',
|
|
51
|
+
version: '1.0.0',
|
|
52
|
+
},
|
|
53
|
+
paths: {},
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Getter for `_spec`
|
|
58
|
+
*/
|
|
59
|
+
get spec(): OpenApiSpec {
|
|
60
|
+
return this._spec;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Setter for `_spec`
|
|
64
|
+
*/
|
|
65
|
+
set spec(value: OpenApiSpec) {
|
|
66
|
+
this._spec = value;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Find an enhancer by its name
|
|
71
|
+
* @param name The name of the enhancer you want to find
|
|
72
|
+
*/
|
|
73
|
+
async getEnhancerByName(name: string): Promise<OASEnhancer | undefined> {
|
|
74
|
+
// Get the latest list of enhancers
|
|
75
|
+
const enhancers = await this.getEnhancers();
|
|
76
|
+
return enhancers.find(e => e.name === name);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Apply a given enhancer's merge function. Return the latest _spec.
|
|
81
|
+
* @param name The name of the enhancer you want to apply
|
|
82
|
+
*/
|
|
83
|
+
async applyEnhancerByName(name: string): Promise<OpenApiSpec> {
|
|
84
|
+
const enhancer = await this.getEnhancerByName(name);
|
|
85
|
+
if (enhancer) this._spec = enhancer.modifySpec(this._spec);
|
|
86
|
+
return this._spec;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Generate OpenAPI spec by applying ALL registered enhancers
|
|
91
|
+
* TBD: load enhancers by group names
|
|
92
|
+
*/
|
|
93
|
+
async applyAllEnhancers(options = {}): Promise<OpenApiSpec> {
|
|
94
|
+
const enhancers = await this.getEnhancers();
|
|
95
|
+
if (_.isEmpty(enhancers)) return this._spec;
|
|
96
|
+
for (const e of enhancers) {
|
|
97
|
+
this._spec = e.modifySpec(this._spec);
|
|
98
|
+
}
|
|
99
|
+
debug(`Spec enhancer service, generated spec: ${inspect(this._spec)}`);
|
|
100
|
+
return this._spec;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* The default merge function to patch the current OpenAPI spec.
|
|
106
|
+
* It leverages module `json-merge-patch`'s merge API to merge two json objects.
|
|
107
|
+
* It returns a new merged object without modifying the original one.
|
|
108
|
+
*
|
|
109
|
+
* A list of merging rules can be found in test file:
|
|
110
|
+
* https://github.com/pierreinglebert/json-merge-patch/blob/master/test/lib/merge.js
|
|
111
|
+
*
|
|
112
|
+
* @param currentSpec The original spec
|
|
113
|
+
* @param patchSpec The patch spec to be merged into the original spec
|
|
114
|
+
*/
|
|
115
|
+
export function mergeOpenAPISpec(
|
|
116
|
+
currentSpec: Partial<OpenApiSpec>,
|
|
117
|
+
patchSpec: Partial<OpenApiSpec>,
|
|
118
|
+
) {
|
|
119
|
+
const mergedSpec = jsonmergepatch.merge(currentSpec, patchSpec);
|
|
120
|
+
return mergedSpec;
|
|
121
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
// Copyright IBM Corp. 2019. All Rights Reserved.
|
|
2
|
+
// Node module: @loopback/openapi-v3
|
|
3
|
+
// This file is licensed under the MIT License.
|
|
4
|
+
// License text available at https://opensource.org/licenses/MIT
|
|
5
|
+
|
|
6
|
+
import {BindingTemplate, extensionFor} from '@loopback/core';
|
|
7
|
+
import {OpenApiSpec} from '../types';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Typically an extension point defines an interface as the contract for
|
|
11
|
+
* extensions to implement
|
|
12
|
+
*/
|
|
13
|
+
export interface OASEnhancer {
|
|
14
|
+
name: string;
|
|
15
|
+
modifySpec(spec: OpenApiSpec): OpenApiSpec;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Name/id of the OAS enhancer extension point
|
|
20
|
+
*/
|
|
21
|
+
export const OAS_ENHANCER_EXTENSION_POINT_NAME = 'oas-enhancer';
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* A binding template for spec contributor extensions
|
|
25
|
+
*/
|
|
26
|
+
export const asSpecEnhancer: BindingTemplate = binding => {
|
|
27
|
+
extensionFor(OAS_ENHANCER_EXTENSION_POINT_NAME)(binding);
|
|
28
|
+
// is it ok to have a different namespace than the extension point name?
|
|
29
|
+
binding.tag({namespace: 'oas-enhancer'});
|
|
30
|
+
};
|
package/src/index.ts
CHANGED
package/src/json-to-schema.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
// License text available at https://opensource.org/licenses/MIT
|
|
5
5
|
|
|
6
6
|
import {JsonSchema} from '@loopback/repository-json-schema';
|
|
7
|
-
import
|
|
7
|
+
import _ from 'lodash';
|
|
8
8
|
import {
|
|
9
9
|
isSchemaObject,
|
|
10
10
|
ReferenceObject,
|
|
@@ -56,13 +56,7 @@ export function jsonToSchemaObject(
|
|
|
56
56
|
[converted]: false,
|
|
57
57
|
};
|
|
58
58
|
visited.set(json, result);
|
|
59
|
-
const propsToIgnore = [
|
|
60
|
-
'anyOf',
|
|
61
|
-
'oneOf',
|
|
62
|
-
'additionalItems',
|
|
63
|
-
'defaultProperties',
|
|
64
|
-
'typeof',
|
|
65
|
-
];
|
|
59
|
+
const propsToIgnore = ['additionalItems', 'defaultProperties', 'typeof'];
|
|
66
60
|
for (const property in json) {
|
|
67
61
|
if (propsToIgnore.includes(property)) {
|
|
68
62
|
continue;
|
|
@@ -83,6 +77,18 @@ export function jsonToSchemaObject(
|
|
|
83
77
|
);
|
|
84
78
|
break;
|
|
85
79
|
}
|
|
80
|
+
case 'anyOf': {
|
|
81
|
+
result.anyOf = _.map(json.anyOf, item =>
|
|
82
|
+
jsonToSchemaObject(item as JsonSchema, visited),
|
|
83
|
+
);
|
|
84
|
+
break;
|
|
85
|
+
}
|
|
86
|
+
case 'oneOf': {
|
|
87
|
+
result.oneOf = _.map(json.oneOf, item =>
|
|
88
|
+
jsonToSchemaObject(item as JsonSchema, visited),
|
|
89
|
+
);
|
|
90
|
+
break;
|
|
91
|
+
}
|
|
86
92
|
case 'definitions': {
|
|
87
93
|
result.definitions = _.mapValues(json.definitions, def =>
|
|
88
94
|
jsonToSchemaObject(jsonOrBooleanToJSON(def), visited),
|
package/src/keys.ts
CHANGED
|
@@ -3,15 +3,10 @@
|
|
|
3
3
|
// This file is licensed under the MIT License.
|
|
4
4
|
// License text available at https://opensource.org/licenses/MIT
|
|
5
5
|
|
|
6
|
-
import {MetadataAccessor} from '@loopback/
|
|
6
|
+
import {MetadataAccessor} from '@loopback/core';
|
|
7
7
|
import {ControllerSpec, RestEndpoint} from './controller-spec';
|
|
8
8
|
import {ParameterObject, RequestBodyObject} from './types';
|
|
9
9
|
|
|
10
|
-
// Copyright IBM Corp. 2018. All Rights Reserved.
|
|
11
|
-
// Node module: @loopback/openapi-v3
|
|
12
|
-
// This file is licensed under the MIT License.
|
|
13
|
-
// License text available at https://opensource.org/licenses/MIT
|
|
14
|
-
|
|
15
10
|
export namespace OAI3Keys {
|
|
16
11
|
/**
|
|
17
12
|
* Metadata key used to set or retrieve `@operation` metadata.
|