@aws/nx-plugin 0.7.0 → 0.8.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/LICENSE-THIRD-PARTY +1682 -108
- package/generators.json +6 -0
- package/package.json +9 -1
- package/src/cloudscape-website/app/generator.js +2 -2
- package/src/cloudscape-website/app/generator.js.map +1 -1
- package/src/infra/app/files/common/constructs/src/core/cfn-guard.ts.template +5 -1
- package/src/infra/app/generator.js +1 -1
- package/src/infra/app/generator.js.map +1 -1
- package/src/open-api/ts-hooks/generator.d.ts +11 -0
- package/src/open-api/ts-hooks/generator.js +17 -0
- package/src/open-api/ts-hooks/generator.js.map +1 -0
- package/src/open-api/ts-hooks/schema.d.ts +9 -0
- package/src/open-api/ts-hooks/schema.json +20 -0
- package/src/open-api/utils/codegen-data/languages.d.ts +10 -0
- package/src/open-api/utils/codegen-data/languages.js +175 -0
- package/src/open-api/utils/codegen-data/languages.js.map +1 -0
- package/src/open-api/utils/codegen-data/types.d.ts +20 -0
- package/src/open-api/utils/codegen-data/types.js +19 -0
- package/src/open-api/utils/codegen-data/types.js.map +1 -0
- package/src/open-api/utils/codegen-data.d.ts +6 -0
- package/src/open-api/utils/codegen-data.js +434 -0
- package/src/open-api/utils/codegen-data.js.map +1 -0
- package/src/open-api/utils/normalise.d.ts +6 -0
- package/src/open-api/utils/normalise.js +213 -0
- package/src/open-api/utils/normalise.js.map +1 -0
- package/src/open-api/utils/parse.d.ts +10 -0
- package/src/open-api/utils/parse.js +38 -0
- package/src/open-api/utils/parse.js.map +1 -0
- package/src/open-api/utils/refs.d.ts +23 -0
- package/src/open-api/utils/refs.js +41 -0
- package/src/open-api/utils/refs.js.map +1 -0
- package/src/open-api/utils/types.d.ts +6 -0
- package/src/open-api/utils/types.js +3 -0
- package/src/open-api/utils/types.js.map +1 -0
- package/src/py/fast-api/__snapshots__/generator.spec.ts.snap +125 -0
- package/src/py/fast-api/files/app/__name__/init.py.template +95 -0
- package/src/py/fast-api/files/app/__name__/main.py.template +3 -4
- package/src/py/fast-api/generator.js +9 -3
- package/src/py/fast-api/generator.js.map +1 -1
- package/src/py/project/generator.js +1 -1
- package/src/py/project/generator.js.map +1 -1
- package/src/trpc/backend/__snapshots__/generator.spec.ts.snap +15 -7
- package/src/trpc/backend/files/backend/src/init.ts.template +3 -0
- package/src/trpc/backend/files/backend/src/middleware/metrics.ts.template +7 -4
- package/src/trpc/backend/generator.js +17 -3
- package/src/trpc/backend/generator.js.map +1 -1
- package/src/ts/lib/generator.js +1 -2
- package/src/ts/lib/generator.js.map +1 -1
- package/src/utils/files/http-api/common/constructs/src/core/http-api.ts.template +5 -3
- package/src/utils/names.d.ts +2 -0
- package/src/utils/names.js +6 -1
- package/src/utils/names.js.map +1 -1
- package/src/utils/nx.d.ts +1 -1
- package/src/utils/nx.js +3 -3
- package/src/utils/nx.js.map +1 -1
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.normaliseOpenApiSpecForCodeGen = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
/**
|
|
6
|
+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
7
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
8
|
+
*/
|
|
9
|
+
const lodash_clonedeepwith_1 = tslib_1.__importDefault(require("lodash.clonedeepwith"));
|
|
10
|
+
const refs_1 = require("./refs");
|
|
11
|
+
const names_1 = require("../../utils/names");
|
|
12
|
+
const isCompositeSchema = (schema) => !!schema.allOf || !!schema.anyOf || !!schema.oneOf;
|
|
13
|
+
const hasSubSchemasToVisit = (schema) => !!schema &&
|
|
14
|
+
!(0, refs_1.isRef)(schema) &&
|
|
15
|
+
(['object', 'array'].includes(schema.type) ||
|
|
16
|
+
isCompositeSchema(schema) ||
|
|
17
|
+
!!schema.not ||
|
|
18
|
+
(schema.type === 'string' && !!schema.enum));
|
|
19
|
+
const filterInlineCompositeSchemas = (schemas, nameParts, namePartPrefix, propPath) => {
|
|
20
|
+
let inlineSchemaIndex = 0;
|
|
21
|
+
return schemas.flatMap((s, i) => {
|
|
22
|
+
if (hasSubSchemasToVisit(s)) {
|
|
23
|
+
const subSchema = {
|
|
24
|
+
nameParts: s.title
|
|
25
|
+
? [(0, names_1.pascalCase)(s.title)]
|
|
26
|
+
: [
|
|
27
|
+
...nameParts,
|
|
28
|
+
`${namePartPrefix}${inlineSchemaIndex === 0 ? '' : inlineSchemaIndex}`,
|
|
29
|
+
],
|
|
30
|
+
schema: s,
|
|
31
|
+
propPath: [...propPath, i],
|
|
32
|
+
};
|
|
33
|
+
inlineSchemaIndex++;
|
|
34
|
+
return [subSchema];
|
|
35
|
+
}
|
|
36
|
+
return [];
|
|
37
|
+
});
|
|
38
|
+
};
|
|
39
|
+
const hoistInlineObjectSubSchemas = (nameParts, schema) => {
|
|
40
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
41
|
+
// Find all the inline subschemas we should visit
|
|
42
|
+
const inlineSubSchemas = [
|
|
43
|
+
...(hasSubSchemasToVisit(schema.not)
|
|
44
|
+
? [
|
|
45
|
+
{
|
|
46
|
+
nameParts: ((_a = schema.not) === null || _a === void 0 ? void 0 : _a.title)
|
|
47
|
+
? [(0, names_1.pascalCase)((_b = schema.not) === null || _b === void 0 ? void 0 : _b.title)]
|
|
48
|
+
: [...nameParts, 'Not'],
|
|
49
|
+
schema: schema.not,
|
|
50
|
+
propPath: ['not'],
|
|
51
|
+
},
|
|
52
|
+
]
|
|
53
|
+
: []),
|
|
54
|
+
...(schema.anyOf
|
|
55
|
+
? filterInlineCompositeSchemas(schema.anyOf, nameParts, 'AnyOf', [
|
|
56
|
+
'anyOf',
|
|
57
|
+
])
|
|
58
|
+
: []),
|
|
59
|
+
...(schema.allOf
|
|
60
|
+
? filterInlineCompositeSchemas(schema.allOf, nameParts, 'AllOf', [
|
|
61
|
+
'allOf',
|
|
62
|
+
])
|
|
63
|
+
: []),
|
|
64
|
+
...(schema.oneOf
|
|
65
|
+
? filterInlineCompositeSchemas(schema.oneOf, nameParts, 'OneOf', [
|
|
66
|
+
'oneOf',
|
|
67
|
+
])
|
|
68
|
+
: []),
|
|
69
|
+
...('items' in schema && hasSubSchemasToVisit(schema.items)
|
|
70
|
+
? [
|
|
71
|
+
{
|
|
72
|
+
nameParts: ((_c = schema.items) === null || _c === void 0 ? void 0 : _c.title)
|
|
73
|
+
? [(0, names_1.pascalCase)((_d = schema.items) === null || _d === void 0 ? void 0 : _d.title)]
|
|
74
|
+
: [...nameParts, 'Item'],
|
|
75
|
+
schema: schema.items,
|
|
76
|
+
propPath: ['items'],
|
|
77
|
+
},
|
|
78
|
+
]
|
|
79
|
+
: []),
|
|
80
|
+
...Object.entries((_e = schema.properties) !== null && _e !== void 0 ? _e : {})
|
|
81
|
+
.filter(([, s]) => hasSubSchemasToVisit(s))
|
|
82
|
+
.map(([name, s]) => ({
|
|
83
|
+
nameParts: s.title
|
|
84
|
+
? [(0, names_1.pascalCase)(s.title)]
|
|
85
|
+
: [...nameParts, name],
|
|
86
|
+
schema: s,
|
|
87
|
+
propPath: ['properties', name],
|
|
88
|
+
})),
|
|
89
|
+
...(typeof schema.additionalProperties !== 'boolean' &&
|
|
90
|
+
hasSubSchemasToVisit(schema.additionalProperties)
|
|
91
|
+
? [
|
|
92
|
+
{
|
|
93
|
+
nameParts: ((_f = schema.additionalProperties) === null || _f === void 0 ? void 0 : _f.title)
|
|
94
|
+
? [(0, names_1.pascalCase)((_g = schema.additionalProperties) === null || _g === void 0 ? void 0 : _g.title)]
|
|
95
|
+
: [...nameParts, 'Value'],
|
|
96
|
+
schema: schema.additionalProperties,
|
|
97
|
+
propPath: ['additionalProperties'],
|
|
98
|
+
},
|
|
99
|
+
]
|
|
100
|
+
: []),
|
|
101
|
+
];
|
|
102
|
+
// Hoist these recursively first (ie depth first search) so that we don't miss refs
|
|
103
|
+
const recursiveRefs = inlineSubSchemas.flatMap((s) => hoistInlineObjectSubSchemas(s.nameParts, s.schema));
|
|
104
|
+
// Clone the object subschemas to build the refs. Note that only objects with "properties" are hoisted as these are non-dictionary types
|
|
105
|
+
const refs = inlineSubSchemas
|
|
106
|
+
.filter((s) => (s.schema.type === 'object' && s.schema.properties) ||
|
|
107
|
+
isCompositeSchema(s.schema) ||
|
|
108
|
+
(s.schema.type === 'string' && s.schema.enum))
|
|
109
|
+
.map((s) => {
|
|
110
|
+
const name = s.nameParts.map(names_1.upperFirst).join('');
|
|
111
|
+
const $ref = `#/components/schemas/${name}`;
|
|
112
|
+
const ref = {
|
|
113
|
+
$ref,
|
|
114
|
+
name,
|
|
115
|
+
schema: structuredClone(Object.assign(Object.assign({}, s.schema), { 'x-aws-nx-hoisted': true })),
|
|
116
|
+
};
|
|
117
|
+
// Replace each subschema with a ref in the spec
|
|
118
|
+
const schemaWithPropToReplace = s.propPath
|
|
119
|
+
.slice(0, -1)
|
|
120
|
+
.reduce((resolvedInSchema, pathPart) => resolvedInSchema === null || resolvedInSchema === void 0 ? void 0 : resolvedInSchema[pathPart], schema);
|
|
121
|
+
if (schemaWithPropToReplace) {
|
|
122
|
+
schemaWithPropToReplace[s.propPath[s.propPath.length - 1]] = { $ref };
|
|
123
|
+
}
|
|
124
|
+
return ref;
|
|
125
|
+
});
|
|
126
|
+
return [...refs, ...recursiveRefs];
|
|
127
|
+
};
|
|
128
|
+
/**
|
|
129
|
+
* In order to ensure we generate models consistently whether or not users used refs or inline schemas,
|
|
130
|
+
* we hoist any inline refs to non-primitives
|
|
131
|
+
*/
|
|
132
|
+
const normaliseOpenApiSpecForCodeGen = (inSpec) => {
|
|
133
|
+
var _a, _b, _c, _d;
|
|
134
|
+
// Clone the spec so we're free to mutate it
|
|
135
|
+
let spec = (0, lodash_clonedeepwith_1.default)(inSpec);
|
|
136
|
+
// Ensure spec has schemas set
|
|
137
|
+
if (!((_a = spec === null || spec === void 0 ? void 0 : spec.components) === null || _a === void 0 ? void 0 : _a.schemas)) {
|
|
138
|
+
spec.components = Object.assign({}, spec.components);
|
|
139
|
+
spec.components.schemas = Object.assign({}, spec.components.schemas);
|
|
140
|
+
}
|
|
141
|
+
// "Hoist" inline request and response schemas
|
|
142
|
+
Object.entries((_b = spec.paths) !== null && _b !== void 0 ? _b : {}).forEach(([path, pathOps]) => Object.entries(pathOps !== null && pathOps !== void 0 ? pathOps : {}).forEach(([method, op]) => {
|
|
143
|
+
var _a, _b, _c, _d;
|
|
144
|
+
const operation = (0, refs_1.resolveIfRef)(spec, op);
|
|
145
|
+
if (operation && typeof operation === 'object') {
|
|
146
|
+
if ('responses' in operation) {
|
|
147
|
+
Object.entries((_a = operation.responses) !== null && _a !== void 0 ? _a : {}).forEach(([code, res]) => {
|
|
148
|
+
var _a, _b, _c;
|
|
149
|
+
const response = (0, refs_1.resolveIfRef)(spec, res);
|
|
150
|
+
const jsonResponseSchema = (_b = (_a = response === null || response === void 0 ? void 0 : response.content) === null || _a === void 0 ? void 0 : _a['application/json']) === null || _b === void 0 ? void 0 : _b.schema;
|
|
151
|
+
if (jsonResponseSchema &&
|
|
152
|
+
!(0, refs_1.isRef)(jsonResponseSchema) &&
|
|
153
|
+
['object', 'array'].includes(jsonResponseSchema.type)) {
|
|
154
|
+
const schemaName = `${(0, names_1.pascalCase)((_c = operation.operationId) !== null && _c !== void 0 ? _c : `${method}-${path}`)}${code}Response`;
|
|
155
|
+
spec.components.schemas[schemaName] = jsonResponseSchema;
|
|
156
|
+
response.content['application/json'].schema = {
|
|
157
|
+
$ref: `#/components/schemas/${schemaName}`,
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
if ('requestBody' in operation) {
|
|
163
|
+
const requestBody = (0, refs_1.resolveIfRef)(spec, operation.requestBody);
|
|
164
|
+
const jsonRequestSchema = (_c = (_b = requestBody === null || requestBody === void 0 ? void 0 : requestBody.content) === null || _b === void 0 ? void 0 : _b['application/json']) === null || _c === void 0 ? void 0 : _c.schema;
|
|
165
|
+
if (jsonRequestSchema &&
|
|
166
|
+
!(0, refs_1.isRef)(jsonRequestSchema) &&
|
|
167
|
+
['object', 'array'].includes(jsonRequestSchema.type)) {
|
|
168
|
+
const schemaName = `${(0, names_1.pascalCase)((_d = operation.operationId) !== null && _d !== void 0 ? _d : `${method}-${path}`)}RequestContent`;
|
|
169
|
+
spec.components.schemas[schemaName] = jsonRequestSchema;
|
|
170
|
+
requestBody.content['application/json'].schema = {
|
|
171
|
+
$ref: `#/components/schemas/${schemaName}`,
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}));
|
|
177
|
+
// "Hoist" any nested object definitions in arrays/maps that aren't already refs, as parseOpenapi will treat the
|
|
178
|
+
// type as "any" if they're defined inline (and not a ref)
|
|
179
|
+
Object.entries((_d = (_c = spec.components) === null || _c === void 0 ? void 0 : _c.schemas) !== null && _d !== void 0 ? _d : {}).forEach(([name, schema]) => {
|
|
180
|
+
if (!(0, refs_1.isRef)(schema)) {
|
|
181
|
+
const refs = hoistInlineObjectSubSchemas([name], schema);
|
|
182
|
+
refs.forEach((ref) => {
|
|
183
|
+
spec.components.schemas[ref.name] = ref.schema;
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
});
|
|
187
|
+
// "Inline" any refs to non objects/enums
|
|
188
|
+
const inlinedRefs = new Set();
|
|
189
|
+
spec = (0, lodash_clonedeepwith_1.default)(spec, (v) => {
|
|
190
|
+
if (v && typeof v === 'object' && v.$ref) {
|
|
191
|
+
const resolved = (0, refs_1.resolveRef)(spec, v.$ref);
|
|
192
|
+
if (resolved &&
|
|
193
|
+
resolved.type &&
|
|
194
|
+
resolved.type !== 'object' &&
|
|
195
|
+
!(resolved.type === 'string' && resolved.enum)) {
|
|
196
|
+
inlinedRefs.add(v.$ref);
|
|
197
|
+
return resolved;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
});
|
|
201
|
+
// Delete the non object schemas that were inlined
|
|
202
|
+
[...inlinedRefs].forEach((ref) => {
|
|
203
|
+
const parts = (0, refs_1.splitRef)(ref);
|
|
204
|
+
if (parts.length === 3 &&
|
|
205
|
+
parts[0] === 'components' &&
|
|
206
|
+
parts[1] === 'schemas') {
|
|
207
|
+
delete spec.components.schemas[parts[2]];
|
|
208
|
+
}
|
|
209
|
+
});
|
|
210
|
+
return spec;
|
|
211
|
+
};
|
|
212
|
+
exports.normaliseOpenApiSpecForCodeGen = normaliseOpenApiSpecForCodeGen;
|
|
213
|
+
//# sourceMappingURL=normalise.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"normalise.js","sourceRoot":"","sources":["../../../../../../packages/nx-plugin/src/open-api/utils/normalise.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
3
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
*/
|
|
5
|
+
import { Tree } from '@nx/devkit';
|
|
6
|
+
import { Spec } from './types';
|
|
7
|
+
/**
|
|
8
|
+
* Parse an OpenAPI specification given its path within the tree
|
|
9
|
+
*/
|
|
10
|
+
export declare const parseOpenApiSpec: (tree: Tree, specPath: string) => Promise<Spec>;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.parseOpenApiSpec = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const swagger_parser_1 = tslib_1.__importDefault(require("@apidevtools/swagger-parser"));
|
|
6
|
+
const TREE_PROTOCOL_PREFIX = 'workspace://';
|
|
7
|
+
/**
|
|
8
|
+
* Parse an OpenAPI specification given its path within the tree
|
|
9
|
+
*/
|
|
10
|
+
const parseOpenApiSpec = (tree, specPath) => tslib_1.__awaiter(void 0, void 0, void 0, function* () {
|
|
11
|
+
// Use a custom protocol prefix to ensure that the swagger parser doesn't try and read from the filesystem itself
|
|
12
|
+
const spec = yield swagger_parser_1.default.bundle(`${TREE_PROTOCOL_PREFIX}/${specPath}`, {
|
|
13
|
+
resolve: {
|
|
14
|
+
// Use a custom resolver which reads files from the tree rather than directly from the filesystem
|
|
15
|
+
file: {
|
|
16
|
+
order: 1,
|
|
17
|
+
read: (file) => {
|
|
18
|
+
const path = file.url.slice(TREE_PROTOCOL_PREFIX.length);
|
|
19
|
+
if (!tree.exists(path)) {
|
|
20
|
+
const message = `Unable to find ${specPath} in workspace ${tree.root}`;
|
|
21
|
+
// Write an error to console as swagger parser's error message may be confusing with our custom protocol prefix
|
|
22
|
+
console.error(message);
|
|
23
|
+
throw new Error(message);
|
|
24
|
+
}
|
|
25
|
+
return tree.read(path);
|
|
26
|
+
},
|
|
27
|
+
canRead: (file) => file.url.startsWith(TREE_PROTOCOL_PREFIX),
|
|
28
|
+
},
|
|
29
|
+
http: false,
|
|
30
|
+
},
|
|
31
|
+
});
|
|
32
|
+
if ('swagger' in spec) {
|
|
33
|
+
throw new Error(`OpenAPI v2 specifications are not supported. Please use OpenAPI v3`);
|
|
34
|
+
}
|
|
35
|
+
return spec;
|
|
36
|
+
});
|
|
37
|
+
exports.parseOpenApiSpec = parseOpenApiSpec;
|
|
38
|
+
//# sourceMappingURL=parse.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parse.js","sourceRoot":"","sources":["../../../../../../packages/nx-plugin/src/open-api/utils/parse.ts"],"names":[],"mappings":";;;;AAKA,yFAAwD;AAGxD,MAAM,oBAAoB,GAAG,cAAc,CAAC;AAE5C;;GAEG;AACI,MAAM,gBAAgB,GAAG,CAC9B,IAAU,EACV,QAAgB,EACD,EAAE;IACjB,iHAAiH;IACjH,MAAM,IAAI,GAAG,MAAM,wBAAa,CAAC,MAAM,CACrC,GAAG,oBAAoB,IAAI,QAAQ,EAAE,EACrC;QACE,OAAO,EAAE;YACP,iGAAiG;YACjG,IAAI,EAAE;gBACJ,KAAK,EAAE,CAAC;gBACR,IAAI,EAAE,CAAC,IAAI,EAAE,EAAE;oBACb,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,oBAAoB,CAAC,MAAM,CAAC,CAAC;oBACzD,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC;wBACvB,MAAM,OAAO,GAAG,kBAAkB,QAAQ,iBAAiB,IAAI,CAAC,IAAI,EAAE,CAAC;wBAEvE,+GAA+G;wBAC/G,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;wBACvB,MAAM,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC;oBAC3B,CAAC;oBACD,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBACzB,CAAC;gBACD,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,oBAAoB,CAAC;aAC7D;YACD,IAAI,EAAE,KAAK;SACZ;KACF,CACF,CAAC;IAEF,IAAI,SAAS,IAAI,IAAI,EAAE,CAAC;QACtB,MAAM,IAAI,KAAK,CACb,oEAAoE,CACrE,CAAC;IACJ,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC,CAAA,CAAC;AApCW,QAAA,gBAAgB,oBAoC3B"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
3
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
*/
|
|
5
|
+
import type { OpenAPIV3 } from 'openapi-types';
|
|
6
|
+
import { Spec } from './types';
|
|
7
|
+
/**
|
|
8
|
+
* Return whether or not the given OpenAPI object is a reference
|
|
9
|
+
*/
|
|
10
|
+
export declare const isRef: (obj: unknown) => obj is OpenAPIV3.ReferenceObject;
|
|
11
|
+
/**
|
|
12
|
+
* Split a reference into its component parts
|
|
13
|
+
* eg: #/components/schemas/Foo -> ["components", "schemas", "Foo"]
|
|
14
|
+
*/
|
|
15
|
+
export declare const splitRef: (ref: string) => string[];
|
|
16
|
+
/**
|
|
17
|
+
* Resolve the given reference in the spec
|
|
18
|
+
*/
|
|
19
|
+
export declare const resolveRef: (spec: Spec, ref: string) => any;
|
|
20
|
+
/**
|
|
21
|
+
* Resolve the given object in an openapi spec if it's a ref
|
|
22
|
+
*/
|
|
23
|
+
export declare const resolveIfRef: <T>(spec: Spec, possibleRef: T | OpenAPIV3.ReferenceObject) => T;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.resolveIfRef = exports.resolveRef = exports.splitRef = exports.isRef = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Return whether or not the given OpenAPI object is a reference
|
|
6
|
+
*/
|
|
7
|
+
const isRef = (obj) => !!obj && typeof obj === 'object' && '$ref' in obj;
|
|
8
|
+
exports.isRef = isRef;
|
|
9
|
+
/**
|
|
10
|
+
* Split a reference into its component parts
|
|
11
|
+
* eg: #/components/schemas/Foo -> ["components", "schemas", "Foo"]
|
|
12
|
+
*/
|
|
13
|
+
const splitRef = (ref) => ref
|
|
14
|
+
.slice(2)
|
|
15
|
+
.split('/')
|
|
16
|
+
.map((p) => p.replace(/~0/g, '~').replace(/~1/g, '/'));
|
|
17
|
+
exports.splitRef = splitRef;
|
|
18
|
+
/**
|
|
19
|
+
* Resolve the given reference in the spec
|
|
20
|
+
*/
|
|
21
|
+
const resolveRef = (spec, ref) => {
|
|
22
|
+
const refParts = (0, exports.splitRef)(ref);
|
|
23
|
+
const resolved = refParts.reduce((resolvedInSpec, refPart) => resolvedInSpec === null || resolvedInSpec === void 0 ? void 0 : resolvedInSpec[refPart], spec);
|
|
24
|
+
if (!resolved) {
|
|
25
|
+
throw new Error(`Unable to resolve ref ${ref} in spec`);
|
|
26
|
+
}
|
|
27
|
+
return resolved;
|
|
28
|
+
};
|
|
29
|
+
exports.resolveRef = resolveRef;
|
|
30
|
+
/**
|
|
31
|
+
* Resolve the given object in an openapi spec if it's a ref
|
|
32
|
+
*/
|
|
33
|
+
const resolveIfRef = (spec, possibleRef) => {
|
|
34
|
+
let resolved = possibleRef;
|
|
35
|
+
if ((0, exports.isRef)(possibleRef)) {
|
|
36
|
+
resolved = (0, exports.resolveRef)(spec, possibleRef.$ref);
|
|
37
|
+
}
|
|
38
|
+
return resolved;
|
|
39
|
+
};
|
|
40
|
+
exports.resolveIfRef = resolveIfRef;
|
|
41
|
+
//# sourceMappingURL=refs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"refs.js","sourceRoot":"","sources":["../../../../../../packages/nx-plugin/src/open-api/utils/refs.ts"],"names":[],"mappings":";;;AAOA;;GAEG;AACI,MAAM,KAAK,GAAG,CAAC,GAAY,EAAoC,EAAE,CACtE,CAAC,CAAC,GAAG,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,MAAM,IAAI,GAAG,CAAC;AADvC,QAAA,KAAK,SACkC;AAEpD;;;GAGG;AACI,MAAM,QAAQ,GAAG,CAAC,GAAW,EAAY,EAAE,CAChD,GAAG;KACA,KAAK,CAAC,CAAC,CAAC;KACR,KAAK,CAAC,GAAG,CAAC;KACV,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,CAAC;AAJ9C,QAAA,QAAQ,YAIsC;AAE3D;;GAEG;AACI,MAAM,UAAU,GAAG,CAAC,IAAU,EAAE,GAAW,EAAO,EAAE;IACzD,MAAM,QAAQ,GAAG,IAAA,gBAAQ,EAAC,GAAG,CAAC,CAAC;IAC/B,MAAM,QAAQ,GAAG,QAAQ,CAAC,MAAM,CAC9B,CAAC,cAAc,EAAE,OAAO,EAAE,EAAE,CAAC,cAAc,aAAd,cAAc,uBAAd,cAAc,CAAG,OAAO,CAAC,EACtD,IAAI,CACL,CAAC;IACF,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,MAAM,IAAI,KAAK,CAAC,yBAAyB,GAAG,UAAU,CAAC,CAAC;IAC1D,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC,CAAC;AAVW,QAAA,UAAU,cAUrB;AAEF;;GAEG;AACI,MAAM,YAAY,GAAG,CAC1B,IAAU,EACV,WAA0C,EACvC,EAAE;IACL,IAAI,QAAQ,GAAG,WAAW,CAAC;IAC3B,IAAI,IAAA,aAAK,EAAC,WAAW,CAAC,EAAE,CAAC;QACvB,QAAQ,GAAG,IAAA,kBAAU,EAAC,IAAI,EAAE,WAAW,CAAC,IAAI,CAAC,CAAC;IAChD,CAAC;IACD,OAAO,QAAa,CAAC;AACvB,CAAC,CAAC;AATW,QAAA,YAAY,gBASvB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../../../../packages/nx-plugin/src/open-api/utils/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
|
2
|
+
|
|
3
|
+
exports[`fastapi project generator > should match snapshot > main-snapshot 1`] = `
|
|
4
|
+
{
|
|
5
|
+
"apps/test_api/test_api/__init__.py": """"Automatically generated by Nx."""
|
|
6
|
+
",
|
|
7
|
+
"apps/test_api/test_api/init.py": "import os
|
|
8
|
+
import uuid
|
|
9
|
+
from collections.abc import Callable
|
|
10
|
+
|
|
11
|
+
from aws_lambda_powertools import Logger, Metrics, Tracer
|
|
12
|
+
from aws_lambda_powertools.metrics import MetricUnit
|
|
13
|
+
from fastapi import FastAPI, Request, Response
|
|
14
|
+
from fastapi.responses import JSONResponse
|
|
15
|
+
from fastapi.routing import APIRoute
|
|
16
|
+
from mangum import Mangum
|
|
17
|
+
from starlette.middleware.exceptions import ExceptionMiddleware
|
|
18
|
+
|
|
19
|
+
os.environ["POWERTOOLS_METRICS_NAMESPACE"] = "TestApi"
|
|
20
|
+
os.environ["POWERTOOLS_SERVICE_NAME"] = "TestApi"
|
|
21
|
+
|
|
22
|
+
logger: Logger = Logger()
|
|
23
|
+
metrics: Metrics = Metrics()
|
|
24
|
+
tracer: Tracer = Tracer()
|
|
25
|
+
|
|
26
|
+
app = FastAPI(
|
|
27
|
+
title="TestApi"
|
|
28
|
+
)
|
|
29
|
+
lambda_handler = Mangum(app)
|
|
30
|
+
|
|
31
|
+
# Add tracing
|
|
32
|
+
lambda_handler.__name__ = "handler" # tracer requires __name__ to be set
|
|
33
|
+
lambda_handler = tracer.capture_lambda_handler(lambda_handler)
|
|
34
|
+
# Add logging
|
|
35
|
+
lambda_handler = logger.inject_lambda_context(lambda_handler, clear_state=True)
|
|
36
|
+
# Add metrics last to properly flush metrics.
|
|
37
|
+
lambda_handler = metrics.log_metrics(lambda_handler, capture_cold_start_metric=True)
|
|
38
|
+
|
|
39
|
+
# Add exception middleware(s)
|
|
40
|
+
app.add_middleware(ExceptionMiddleware, handlers=app.exception_handlers)
|
|
41
|
+
|
|
42
|
+
@app.exception_handler(Exception)
|
|
43
|
+
async def unhandled_exception_handler(request, err):
|
|
44
|
+
logger.exception("Unhandled exception")
|
|
45
|
+
|
|
46
|
+
metrics.add_metric(name="Failure", unit=MetricUnit.Count, value=1)
|
|
47
|
+
|
|
48
|
+
return JSONResponse(status_code=500, content={"detail": "Internal Server Error"})
|
|
49
|
+
|
|
50
|
+
@app.middleware("http")
|
|
51
|
+
async def metrics_handler(request: Request, call_next):
|
|
52
|
+
metrics.add_dimension("route", f"{request.method} {request.url.path}")
|
|
53
|
+
metrics.add_metric(name="RequestCount", unit=MetricUnit.Count, value=1)
|
|
54
|
+
|
|
55
|
+
response = await call_next(request)
|
|
56
|
+
|
|
57
|
+
if response.status_code == 200:
|
|
58
|
+
metrics.add_metric(name="Success", unit=MetricUnit.Count, value=1)
|
|
59
|
+
|
|
60
|
+
return response
|
|
61
|
+
|
|
62
|
+
# Add correlation id middleware
|
|
63
|
+
@app.middleware("http")
|
|
64
|
+
async def add_correlation_id(request: Request, call_next):
|
|
65
|
+
# Get correlation id from X-Correlation-Id header
|
|
66
|
+
corr_id = request.headers.get("x-correlation-id")
|
|
67
|
+
if not corr_id and "aws.context" in request.scope:
|
|
68
|
+
# If empty, use request id from aws context
|
|
69
|
+
corr_id = request.scope["aws.context"].aws_request_id
|
|
70
|
+
elif not corr_id:
|
|
71
|
+
# If still empty, use uuid
|
|
72
|
+
corr_id = uuid.uuid4().hex
|
|
73
|
+
|
|
74
|
+
# Add correlation id to logs
|
|
75
|
+
logger.set_correlation_id(corr_id)
|
|
76
|
+
|
|
77
|
+
response = await call_next(request)
|
|
78
|
+
|
|
79
|
+
# Return correlation header in response
|
|
80
|
+
response.headers["X-Correlation-Id"] = corr_id
|
|
81
|
+
return response
|
|
82
|
+
|
|
83
|
+
class LoggerRouteHandler(APIRoute):
|
|
84
|
+
def get_route_handler(self) -> Callable:
|
|
85
|
+
original_route_handler = super().get_route_handler()
|
|
86
|
+
|
|
87
|
+
async def route_handler(request: Request) -> Response:
|
|
88
|
+
# Add fastapi context to logs
|
|
89
|
+
ctx = {
|
|
90
|
+
"path": request.url.path,
|
|
91
|
+
"route": self.path,
|
|
92
|
+
"method": request.method,
|
|
93
|
+
}
|
|
94
|
+
logger.append_keys(fastapi=ctx)
|
|
95
|
+
logger.info("Received request")
|
|
96
|
+
|
|
97
|
+
return await original_route_handler(request)
|
|
98
|
+
|
|
99
|
+
return route_handler
|
|
100
|
+
|
|
101
|
+
app.router.route_class = LoggerRouteHandler",
|
|
102
|
+
"apps/test_api/test_api/main.py": "from .init import app, lambda_handler, tracer
|
|
103
|
+
|
|
104
|
+
handler = lambda_handler
|
|
105
|
+
|
|
106
|
+
@app.get("/")
|
|
107
|
+
@tracer.capture_method
|
|
108
|
+
def read_root():
|
|
109
|
+
return {"Hello": "World"}",
|
|
110
|
+
"apps/test_api/tests/__init__.py": """"unit tests."""
|
|
111
|
+
",
|
|
112
|
+
"apps/test_api/tests/conftest.py": """"Unit tests configuration module."""
|
|
113
|
+
|
|
114
|
+
pytest_plugins = []
|
|
115
|
+
",
|
|
116
|
+
"apps/test_api/tests/test_main.py": "#
|
|
117
|
+
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
118
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
119
|
+
#
|
|
120
|
+
|
|
121
|
+
def test_main():
|
|
122
|
+
pass
|
|
123
|
+
",
|
|
124
|
+
}
|
|
125
|
+
`;
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import uuid
|
|
3
|
+
from collections.abc import Callable
|
|
4
|
+
|
|
5
|
+
from aws_lambda_powertools import Logger, Metrics, Tracer
|
|
6
|
+
from aws_lambda_powertools.metrics import MetricUnit
|
|
7
|
+
from fastapi import FastAPI, Request, Response
|
|
8
|
+
from fastapi.responses import JSONResponse
|
|
9
|
+
from fastapi.routing import APIRoute
|
|
10
|
+
from mangum import Mangum
|
|
11
|
+
from starlette.middleware.exceptions import ExceptionMiddleware
|
|
12
|
+
|
|
13
|
+
os.environ["POWERTOOLS_METRICS_NAMESPACE"] = "<%= apiNameClassName %>"
|
|
14
|
+
os.environ["POWERTOOLS_SERVICE_NAME"] = "<%= apiNameClassName %>"
|
|
15
|
+
|
|
16
|
+
logger: Logger = Logger()
|
|
17
|
+
metrics: Metrics = Metrics()
|
|
18
|
+
tracer: Tracer = Tracer()
|
|
19
|
+
|
|
20
|
+
app = FastAPI(
|
|
21
|
+
title="<%= apiNameClassName %>"
|
|
22
|
+
)
|
|
23
|
+
lambda_handler = Mangum(app)
|
|
24
|
+
|
|
25
|
+
# Add tracing
|
|
26
|
+
lambda_handler.__name__ = "handler" # tracer requires __name__ to be set
|
|
27
|
+
lambda_handler = tracer.capture_lambda_handler(lambda_handler)
|
|
28
|
+
# Add logging
|
|
29
|
+
lambda_handler = logger.inject_lambda_context(lambda_handler, clear_state=True)
|
|
30
|
+
# Add metrics last to properly flush metrics.
|
|
31
|
+
lambda_handler = metrics.log_metrics(lambda_handler, capture_cold_start_metric=True)
|
|
32
|
+
|
|
33
|
+
# Add exception middleware(s)
|
|
34
|
+
app.add_middleware(ExceptionMiddleware, handlers=app.exception_handlers)
|
|
35
|
+
|
|
36
|
+
@app.exception_handler(Exception)
|
|
37
|
+
async def unhandled_exception_handler(request, err):
|
|
38
|
+
logger.exception("Unhandled exception")
|
|
39
|
+
|
|
40
|
+
metrics.add_metric(name="Failure", unit=MetricUnit.Count, value=1)
|
|
41
|
+
|
|
42
|
+
return JSONResponse(status_code=500, content={"detail": "Internal Server Error"})
|
|
43
|
+
|
|
44
|
+
@app.middleware("http")
|
|
45
|
+
async def metrics_handler(request: Request, call_next):
|
|
46
|
+
metrics.add_dimension("route", f"{request.method} {request.url.path}")
|
|
47
|
+
metrics.add_metric(name="RequestCount", unit=MetricUnit.Count, value=1)
|
|
48
|
+
|
|
49
|
+
response = await call_next(request)
|
|
50
|
+
|
|
51
|
+
if response.status_code == 200:
|
|
52
|
+
metrics.add_metric(name="Success", unit=MetricUnit.Count, value=1)
|
|
53
|
+
|
|
54
|
+
return response
|
|
55
|
+
|
|
56
|
+
# Add correlation id middleware
|
|
57
|
+
@app.middleware("http")
|
|
58
|
+
async def add_correlation_id(request: Request, call_next):
|
|
59
|
+
# Get correlation id from X-Correlation-Id header
|
|
60
|
+
corr_id = request.headers.get("x-correlation-id")
|
|
61
|
+
if not corr_id and "aws.context" in request.scope:
|
|
62
|
+
# If empty, use request id from aws context
|
|
63
|
+
corr_id = request.scope["aws.context"].aws_request_id
|
|
64
|
+
elif not corr_id:
|
|
65
|
+
# If still empty, use uuid
|
|
66
|
+
corr_id = uuid.uuid4().hex
|
|
67
|
+
|
|
68
|
+
# Add correlation id to logs
|
|
69
|
+
logger.set_correlation_id(corr_id)
|
|
70
|
+
|
|
71
|
+
response = await call_next(request)
|
|
72
|
+
|
|
73
|
+
# Return correlation header in response
|
|
74
|
+
response.headers["X-Correlation-Id"] = corr_id
|
|
75
|
+
return response
|
|
76
|
+
|
|
77
|
+
class LoggerRouteHandler(APIRoute):
|
|
78
|
+
def get_route_handler(self) -> Callable:
|
|
79
|
+
original_route_handler = super().get_route_handler()
|
|
80
|
+
|
|
81
|
+
async def route_handler(request: Request) -> Response:
|
|
82
|
+
# Add fastapi context to logs
|
|
83
|
+
ctx = {
|
|
84
|
+
"path": request.url.path,
|
|
85
|
+
"route": self.path,
|
|
86
|
+
"method": request.method,
|
|
87
|
+
}
|
|
88
|
+
logger.append_keys(fastapi=ctx)
|
|
89
|
+
logger.info("Received request")
|
|
90
|
+
|
|
91
|
+
return await original_route_handler(request)
|
|
92
|
+
|
|
93
|
+
return route_handler
|
|
94
|
+
|
|
95
|
+
app.router.route_class = LoggerRouteHandler
|
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
from
|
|
2
|
-
from mangum import Mangum
|
|
1
|
+
from .init import app, lambda_handler, tracer
|
|
3
2
|
|
|
4
|
-
|
|
5
|
-
handler = Mangum(app)
|
|
3
|
+
handler = lambda_handler
|
|
6
4
|
|
|
7
5
|
@app.get("/")
|
|
6
|
+
@tracer.capture_method
|
|
8
7
|
def read_root():
|
|
9
8
|
return {"Hello": "World"}
|
|
@@ -48,7 +48,7 @@ const fastApiProjectGenerator = (tree, schema) => tslib_1.__awaiter(void 0, void
|
|
|
48
48
|
options: {
|
|
49
49
|
commands: [
|
|
50
50
|
`uv export --frozen --no-dev --no-editable --project ${normalizedName} -o dist/${dir}/bundle/requirements.txt`,
|
|
51
|
-
`uv pip install --no-installer-metadata --no-compile-bytecode --python-platform x86_64-manylinux2014 --python \`uv python pin\` --target dist/${dir}/bundle -r dist/${dir}/bundle/requirements.txt
|
|
51
|
+
`uv pip install -n --no-installer-metadata --no-compile-bytecode --python-platform x86_64-manylinux2014 --python \`uv python pin\` --target dist/${dir}/bundle -r dist/${dir}/bundle/requirements.txt`,
|
|
52
52
|
],
|
|
53
53
|
parallel: false,
|
|
54
54
|
},
|
|
@@ -69,7 +69,7 @@ const fastApiProjectGenerator = (tree, schema) => tslib_1.__awaiter(void 0, void
|
|
|
69
69
|
apiName: schema.name,
|
|
70
70
|
apiType: 'fast-api',
|
|
71
71
|
};
|
|
72
|
-
projectConfig.targets = (0, nx_1.
|
|
72
|
+
projectConfig.targets = (0, nx_1.sortObjectKeys)(projectConfig.targets);
|
|
73
73
|
(0, devkit_1.updateProjectConfiguration)(tree, normalizedName, projectConfig);
|
|
74
74
|
[
|
|
75
75
|
(0, devkit_1.joinPathFragments)(dir, normalizedModuleName !== null && normalizedModuleName !== void 0 ? normalizedModuleName : normalizedName, 'hello.py'),
|
|
@@ -80,6 +80,7 @@ const fastApiProjectGenerator = (tree, schema) => tslib_1.__awaiter(void 0, void
|
|
|
80
80
|
dir, // destination path of the files
|
|
81
81
|
{
|
|
82
82
|
name: normalizedName,
|
|
83
|
+
apiNameClassName,
|
|
83
84
|
}, {
|
|
84
85
|
overwriteStrategy: devkit_1.OverwriteStrategy.Overwrite,
|
|
85
86
|
});
|
|
@@ -106,7 +107,12 @@ const fastApiProjectGenerator = (tree, schema) => tslib_1.__awaiter(void 0, void
|
|
|
106
107
|
return config;
|
|
107
108
|
});
|
|
108
109
|
const projectToml = (0, toml_1.parse)(tree.read((0, devkit_1.joinPathFragments)(dir, 'pyproject.toml'), 'utf8'));
|
|
109
|
-
projectToml.project.dependencies = [
|
|
110
|
+
projectToml.project.dependencies = [
|
|
111
|
+
'fastapi',
|
|
112
|
+
'mangum',
|
|
113
|
+
'aws-lambda-powertools',
|
|
114
|
+
'aws-lambda-powertools[tracer]',
|
|
115
|
+
].concat(((_b = projectToml.project) === null || _b === void 0 ? void 0 : _b.dependencies) || []);
|
|
110
116
|
projectToml['dependency-groups'] = { dev: ['fastapi[standard]>=0.115'] };
|
|
111
117
|
tree.write((0, devkit_1.joinPathFragments)(dir, 'pyproject.toml'), (0, toml_1.stringify)(projectToml));
|
|
112
118
|
yield (0, format_1.formatFilesInSubtree)(tree);
|