@backstage/backend-openapi-utils 0.0.0-nightly-20230407021743
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 +7 -0
- package/README.md +45 -0
- package/dist/index.cjs.js +10 -0
- package/dist/index.cjs.js.map +1 -0
- package/dist/index.d.ts +539 -0
- package/package.json +41 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# @backstage/backend-openapi-utils
|
|
2
|
+
|
|
3
|
+
## 0.0.0-nightly-20230407021743
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 62fe726fdc5: New plugin! Primary focus is to support types on `Router`s in backend packages. Developers can use the `ApiRouter` from this package in their packages to support a typed experience based on their OpenAPI specs. The `ApiRouter` supports request bodies, response bodies, query parameters and path parameters, as well as full path-based context of the above. This means no more guessing on an endpoint like `req.post('/not-my-route', (req, res)=>{res.send(req.body.badparam)})`. Typescript would catch `/not-my-route`, `req.body.badparam`, `res.send(req.body.badparam)`.
|
package/README.md
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# @backstage/openapi-utils
|
|
2
|
+
|
|
3
|
+
## Summary
|
|
4
|
+
|
|
5
|
+
This package is meant to provide a typed Express router for an OpenAPI spec. Based on the [`oatx`](https://github.com/varanauskas/oatx) library and adapted to override Express values.
|
|
6
|
+
|
|
7
|
+
## Getting Started
|
|
8
|
+
|
|
9
|
+
### Configuration
|
|
10
|
+
|
|
11
|
+
1. Run `yarn --cwd <package-dir> backstage-cli package schema:openapi:generate` to translate your `src/schema/openapi.yaml` to a new Typescript file in `src/schema/openapi.ts`. In the case of projects that require linting + a license header, you will need to do this manually.
|
|
12
|
+
|
|
13
|
+
2. In your plugin's `src/service/createRouter.ts`,
|
|
14
|
+
|
|
15
|
+
```ts
|
|
16
|
+
import {ApiRouter} from `@backstage/backend-openapi-utils`;
|
|
17
|
+
import spec from '../schema/openapi'
|
|
18
|
+
...
|
|
19
|
+
|
|
20
|
+
export function createRouter(){
|
|
21
|
+
const router = Router() as ApiRouter<typeof spec>;
|
|
22
|
+
...
|
|
23
|
+
}
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
### Limitations
|
|
27
|
+
|
|
28
|
+
1. `as const` makes all fields `readonly`
|
|
29
|
+
To ensure a good DX of using a simple imported JSON spec, we want to remove any type issues between `readonly` arrays and mutable arrays. Typescript does not allow them to be compared, so converting all imports from the `openapi3-ts` library to `readonly` is important. This is achieved through the `ImmutableObject` type in `types/immutable.ts`.
|
|
30
|
+
|
|
31
|
+
```ts
|
|
32
|
+
...
|
|
33
|
+
// We want an interface like this,
|
|
34
|
+
Router() as ApiRouter<typeof spec>
|
|
35
|
+
|
|
36
|
+
// Not an interface like this,
|
|
37
|
+
Router() as ApiRouter<DeepWriteable<typeof spec>>
|
|
38
|
+
...
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Future Work
|
|
42
|
+
|
|
43
|
+
### Runtime validation
|
|
44
|
+
|
|
45
|
+
Using a package like [`express-openapi-validator`](https://www.npmjs.com/package/express-openapi-validator), would allow us to remove [validation of request bodies with `AJV`](https://github.com/backstage/backstage/blob/master/plugins/catalog-backend/src/service/util.ts#L58). However, `AJV` currently doesn't have support for OpenAPI 3.1 and `express-openapi-validator` enforces full URL matching for paths, meaning it cannot be mounted at the router level.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.cjs.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,539 @@
|
|
|
1
|
+
import { JSONSchema7, FromSchema } from 'json-schema-to-ts';
|
|
2
|
+
import { ReferenceObject, OpenAPIObject, ContentObject, RequestBodyObject, ResponseObject, ParameterObject, SchemaObject } from 'openapi3-ts';
|
|
3
|
+
import core from 'express-serve-static-core';
|
|
4
|
+
import { Router } from 'express';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* This file is meant to hold Immutable overwrites of the values provided by the `openapi3-ts`
|
|
8
|
+
* package due to issues with `as const` supporting only readonly values.
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* From {@link https://github.com/microsoft/TypeScript/issues/13923#issuecomment-653675557}, allows
|
|
12
|
+
* us to convert from `as const` to the various OpenAPI types documented in `openapi3-ts`.
|
|
13
|
+
*
|
|
14
|
+
* @public
|
|
15
|
+
*/
|
|
16
|
+
type Immutable<T> = T extends Function | boolean | number | string | null | undefined ? T : T extends Map<infer K, infer V> ? ReadonlyMap<Immutable<K>, Immutable<V>> : T extends Set<infer S> ? ReadonlySet<Immutable<S>> : {
|
|
17
|
+
readonly [P in keyof T]: Immutable<T[P]>;
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* @public
|
|
21
|
+
*/
|
|
22
|
+
type ImmutableObject<T> = {
|
|
23
|
+
readonly [K in keyof T]: Immutable<T[K]>;
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* @public
|
|
27
|
+
*/
|
|
28
|
+
type ImmutableReferenceObject = ImmutableObject<ReferenceObject>;
|
|
29
|
+
/**
|
|
30
|
+
* @public
|
|
31
|
+
*/
|
|
32
|
+
type ImmutableOpenAPIObject = ImmutableObject<OpenAPIObject>;
|
|
33
|
+
/**
|
|
34
|
+
* @public
|
|
35
|
+
*/
|
|
36
|
+
type ImmutableContentObject = ImmutableObject<ContentObject>;
|
|
37
|
+
/**
|
|
38
|
+
* @public
|
|
39
|
+
*/
|
|
40
|
+
type ImmutableRequestBodyObject = ImmutableObject<RequestBodyObject>;
|
|
41
|
+
/**
|
|
42
|
+
* @public
|
|
43
|
+
*/
|
|
44
|
+
type ImmutableResponseObject = ImmutableObject<ResponseObject>;
|
|
45
|
+
/**
|
|
46
|
+
* @public
|
|
47
|
+
*/
|
|
48
|
+
type ImmutableParameterObject = ImmutableObject<ParameterObject>;
|
|
49
|
+
/**
|
|
50
|
+
* @public
|
|
51
|
+
*/
|
|
52
|
+
interface HeaderObject extends ParameterObject {
|
|
53
|
+
in: 'header';
|
|
54
|
+
style: 'simple';
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* @public
|
|
58
|
+
*/
|
|
59
|
+
type ImmutableHeaderObject = ImmutableObject<HeaderObject>;
|
|
60
|
+
/**
|
|
61
|
+
* @public
|
|
62
|
+
*/
|
|
63
|
+
interface CookieObject extends ParameterObject {
|
|
64
|
+
in: 'cookie';
|
|
65
|
+
style?: 'form';
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* @public
|
|
69
|
+
*/
|
|
70
|
+
type ImmutableCookieObject = ImmutableObject<CookieObject>;
|
|
71
|
+
/**
|
|
72
|
+
* @public
|
|
73
|
+
*/
|
|
74
|
+
interface QueryObject extends ParameterObject {
|
|
75
|
+
in: 'query';
|
|
76
|
+
style?: 'form' | 'deepObject' | 'pipeDelimited' | 'spaceDelimited';
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* @public
|
|
80
|
+
*/
|
|
81
|
+
type ImmutableQueryObject = ImmutableObject<QueryObject>;
|
|
82
|
+
/**
|
|
83
|
+
* @public
|
|
84
|
+
*/
|
|
85
|
+
interface PathObject extends ParameterObject {
|
|
86
|
+
in: 'path';
|
|
87
|
+
style?: 'simple' | 'label' | 'matrix';
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* @public
|
|
91
|
+
*/
|
|
92
|
+
type ImmutablePathObject = ImmutableObject<PathObject>;
|
|
93
|
+
/**
|
|
94
|
+
* @public
|
|
95
|
+
*/
|
|
96
|
+
type ImmutableSchemaObject = ImmutableObject<SchemaObject>;
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Pulled from https://github.com/varanauskas/oatx.
|
|
100
|
+
*/
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Basic OpenAPI spec with paths and components properties enforced.
|
|
104
|
+
* @public
|
|
105
|
+
*/
|
|
106
|
+
type RequiredDoc = Pick<ImmutableOpenAPIObject, 'paths' | 'components'>;
|
|
107
|
+
/**
|
|
108
|
+
* @public
|
|
109
|
+
*/
|
|
110
|
+
type PathDoc = Pick<ImmutableOpenAPIObject, 'paths'>;
|
|
111
|
+
/**
|
|
112
|
+
* Get value types of `T`.
|
|
113
|
+
* @public
|
|
114
|
+
*/
|
|
115
|
+
type ValueOf<T> = T[keyof T];
|
|
116
|
+
/**
|
|
117
|
+
* Validate a string against OpenAPI path template, {@link https://spec.openapis.org/oas/v3.1.0#path-templating-matching}.
|
|
118
|
+
*
|
|
119
|
+
* @example
|
|
120
|
+
* ```ts
|
|
121
|
+
* const path: PathTemplate<"/posts/{postId}/comments/{commentId}"> = "/posts/:postId/comments/:commentId";
|
|
122
|
+
* const pathWithoutParams: PathTemplate<"/posts/comments"> = "/posts/comments";
|
|
123
|
+
* ```
|
|
124
|
+
*
|
|
125
|
+
* @public
|
|
126
|
+
*/
|
|
127
|
+
type PathTemplate<Path extends string> = Path extends `${infer Prefix}{${infer PathName}}${infer Suffix}` ? `${Prefix}:${PathName}${PathTemplate<Suffix>}` : Path;
|
|
128
|
+
/**
|
|
129
|
+
* Extract path as specified in OpenAPI `Doc` based on request path
|
|
130
|
+
* @example
|
|
131
|
+
* ```ts
|
|
132
|
+
* const spec = {
|
|
133
|
+
* paths: {
|
|
134
|
+
* "/posts/{postId}/comments/{commentId}": {},
|
|
135
|
+
* "/posts/comments": {},
|
|
136
|
+
* }
|
|
137
|
+
* };
|
|
138
|
+
* const specPathWithParams: DocPath<typeof spec, "/posts/:postId/comments/:commentId"> = "/posts/{postId}/comments/{commentId}";
|
|
139
|
+
* const specPathWithoutParams: DocPath<typeof spec, "/posts/comments"> = "/posts/comments";
|
|
140
|
+
* ```
|
|
141
|
+
*
|
|
142
|
+
* @public
|
|
143
|
+
*/
|
|
144
|
+
type DocPath<Doc extends PathDoc, Path extends PathTemplate<Extract<keyof Doc['paths'], string>>> = ValueOf<{
|
|
145
|
+
[Template in Extract<keyof Doc['paths'], string>]: Path extends PathTemplate<Template> ? Template : never;
|
|
146
|
+
}>;
|
|
147
|
+
/**
|
|
148
|
+
* @public
|
|
149
|
+
*/
|
|
150
|
+
type DocPathTemplate<Doc extends PathDoc> = PathTemplate<Extract<keyof Doc['paths'], string>>;
|
|
151
|
+
/**
|
|
152
|
+
* @public
|
|
153
|
+
*/
|
|
154
|
+
type DocPathMethod<Doc extends Pick<RequiredDoc, 'paths'>, Path extends DocPathTemplate<Doc>> = keyof Doc['paths'][DocPath<Doc, Path>];
|
|
155
|
+
/**
|
|
156
|
+
* @public
|
|
157
|
+
*/
|
|
158
|
+
type MethodAwareDocPath<Doc extends PathDoc, Path extends PathTemplate<Extract<keyof Doc['paths'], string>>, Method extends keyof Doc['paths'][Path]> = ValueOf<{
|
|
159
|
+
[Template in Extract<keyof Doc['paths'], string>]: Path extends PathTemplate<Template> ? Method extends DocPathMethod<Doc, Path> ? PathTemplate<Template> : never : never;
|
|
160
|
+
}>;
|
|
161
|
+
/**
|
|
162
|
+
* @public
|
|
163
|
+
*/
|
|
164
|
+
type DocOperation<Doc extends RequiredDoc, Path extends keyof Doc['paths'], Method extends keyof Doc['paths'][Path]> = Doc['paths'][Path][Method];
|
|
165
|
+
/**
|
|
166
|
+
* @public
|
|
167
|
+
*/
|
|
168
|
+
type ComponentTypes<Doc extends RequiredDoc> = Extract<keyof Doc['components'], string>;
|
|
169
|
+
/**
|
|
170
|
+
* @public
|
|
171
|
+
*/
|
|
172
|
+
type ComponentRef<Doc extends RequiredDoc, Type extends ComponentTypes<Doc>, Ref extends ImmutableReferenceObject> = Ref extends {
|
|
173
|
+
$ref: `#/components/${Type}/${infer Name}`;
|
|
174
|
+
} ? Name extends keyof Doc['components'][Type] ? Doc['components'][Type][Name] extends ImmutableReferenceObject ? ComponentRef<Doc, Type, Doc['components'][Type][Name]> : Doc['components'][Type][Name] : never : never;
|
|
175
|
+
/**
|
|
176
|
+
* @public
|
|
177
|
+
*/
|
|
178
|
+
type SchemaRef<Doc extends RequiredDoc, Schema> = Schema extends {
|
|
179
|
+
$ref: `#/components/schemas/${infer Name}`;
|
|
180
|
+
} ? 'schemas' extends keyof Doc['components'] ? Name extends keyof Doc['components']['schemas'] ? SchemaRef<Doc, Doc['components']['schemas'][Name]> : never : never : {
|
|
181
|
+
[Key in keyof Schema]: SchemaRef<Doc, Schema[Key]>;
|
|
182
|
+
};
|
|
183
|
+
/**
|
|
184
|
+
* @public
|
|
185
|
+
*/
|
|
186
|
+
type ObjectWithContentSchema<Doc extends RequiredDoc, Object extends {
|
|
187
|
+
content?: ImmutableContentObject;
|
|
188
|
+
}> = Object['content'] extends ImmutableContentObject ? SchemaRef<Doc, Object['content']['application/json']['schema']> : never;
|
|
189
|
+
/**
|
|
190
|
+
* From {@link https://stackoverflow.com/questions/71393738/typescript-intersection-not-union-type-from-json-schema}
|
|
191
|
+
*
|
|
192
|
+
* StackOverflow says not to do this, but union types aren't possible any other way.
|
|
193
|
+
*
|
|
194
|
+
* @public
|
|
195
|
+
*/
|
|
196
|
+
type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends (k: infer I) => void ? I : never;
|
|
197
|
+
/**
|
|
198
|
+
* @public
|
|
199
|
+
*/
|
|
200
|
+
type LastOf<T> = UnionToIntersection<T extends any ? () => T : never> extends () => infer R ? R : never;
|
|
201
|
+
/**
|
|
202
|
+
* @public
|
|
203
|
+
*/
|
|
204
|
+
type Push<T extends any[], V> = [...T, V];
|
|
205
|
+
/**
|
|
206
|
+
* @public
|
|
207
|
+
*/
|
|
208
|
+
type TuplifyUnion<T, L = LastOf<T>, N = [T] extends [never] ? true : false> = true extends N ? [] : Push<TuplifyUnion<Exclude<T, L>>, L>;
|
|
209
|
+
/**
|
|
210
|
+
* @public
|
|
211
|
+
*/
|
|
212
|
+
type ConvertAll<T, R extends ReadonlyArray<unknown> = []> = T extends [
|
|
213
|
+
infer First extends JSONSchema7,
|
|
214
|
+
...infer Rest
|
|
215
|
+
] ? ConvertAll<Rest, [...R, FromSchema<First>]> : R;
|
|
216
|
+
/**
|
|
217
|
+
* @public
|
|
218
|
+
*/
|
|
219
|
+
type UnknownIfNever<P> = [P] extends [never] ? unknown : P;
|
|
220
|
+
/**
|
|
221
|
+
* @public
|
|
222
|
+
*/
|
|
223
|
+
type ToTypeSafe<T> = UnknownIfNever<ConvertAll<TuplifyUnion<T>>[number]>;
|
|
224
|
+
/**
|
|
225
|
+
* @public
|
|
226
|
+
*/
|
|
227
|
+
type DiscriminateUnion<T, K extends keyof T, V extends T[K]> = Extract<T, Record<K, V>>;
|
|
228
|
+
/**
|
|
229
|
+
* @public
|
|
230
|
+
*/
|
|
231
|
+
type MapDiscriminatedUnion<T extends Record<K, string>, K extends keyof T> = {
|
|
232
|
+
[V in T[K]]: DiscriminateUnion<T, K, V>;
|
|
233
|
+
};
|
|
234
|
+
/**
|
|
235
|
+
* @public
|
|
236
|
+
*/
|
|
237
|
+
type PickOptionalKeys<T extends {
|
|
238
|
+
[key: string]: any;
|
|
239
|
+
}> = {
|
|
240
|
+
[K in keyof T]: true extends T[K]['required'] ? never : K;
|
|
241
|
+
}[keyof T];
|
|
242
|
+
/**
|
|
243
|
+
* @public
|
|
244
|
+
*/
|
|
245
|
+
type PickRequiredKeys<T extends {
|
|
246
|
+
[key: string]: any;
|
|
247
|
+
}> = {
|
|
248
|
+
[K in keyof T]: true extends T[K]['required'] ? K : never;
|
|
249
|
+
}[keyof T];
|
|
250
|
+
/**
|
|
251
|
+
* @public
|
|
252
|
+
*/
|
|
253
|
+
type OptionalMap<T extends {
|
|
254
|
+
[key: string]: any;
|
|
255
|
+
}> = {
|
|
256
|
+
[P in Exclude<PickOptionalKeys<T>, undefined>]?: NonNullable<T[P]>;
|
|
257
|
+
};
|
|
258
|
+
/**
|
|
259
|
+
* @public
|
|
260
|
+
*/
|
|
261
|
+
type RequiredMap<T extends {
|
|
262
|
+
[key: string]: any;
|
|
263
|
+
}> = {
|
|
264
|
+
[P in Exclude<PickRequiredKeys<T>, undefined>]: NonNullable<T[P]>;
|
|
265
|
+
};
|
|
266
|
+
/**
|
|
267
|
+
* @public
|
|
268
|
+
*/
|
|
269
|
+
type FullMap<T extends {
|
|
270
|
+
[key: string]: any;
|
|
271
|
+
}> = RequiredMap<T> & OptionalMap<T>;
|
|
272
|
+
/**
|
|
273
|
+
* @public
|
|
274
|
+
*/
|
|
275
|
+
type Filter<T, U> = T extends U ? T : never;
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* @public
|
|
279
|
+
*/
|
|
280
|
+
type DocParameter<Doc extends RequiredDoc, Path extends Extract<keyof Doc['paths'], string>, Method extends keyof Doc['paths'][Path], Parameter extends keyof Doc['paths'][Path][Method]['parameters']> = DocOperation<Doc, Path, Method>['parameters'][Parameter] extends ImmutableReferenceObject ? 'parameters' extends ComponentTypes<Doc> ? ComponentRef<Doc, 'parameters', DocOperation<Doc, Path, Method>['parameters'][Parameter]> : never : DocOperation<Doc, Path, Method>['parameters'][Parameter];
|
|
281
|
+
/**
|
|
282
|
+
* @public
|
|
283
|
+
*/
|
|
284
|
+
type DocParameters<Doc extends RequiredDoc, Path extends Extract<keyof Doc['paths'], string>, Method extends keyof Doc['paths'][Path]> = DocOperation<Doc, Path, Method>['parameters'] extends ReadonlyArray<any> ? {
|
|
285
|
+
[Index in keyof DocOperation<Doc, Path, Method>['parameters']]: DocParameter<Doc, Path, Method, Index>;
|
|
286
|
+
} : never;
|
|
287
|
+
/**
|
|
288
|
+
* @public
|
|
289
|
+
*/
|
|
290
|
+
type ResolveDocParameterSchema<Doc extends RequiredDoc, Schema extends ImmutableParameterObject['schema']> = Schema extends ImmutableReferenceObject ? 'parameters' extends ComponentTypes<Doc> ? ComponentRef<Doc, 'parameters', Schema> : never : Schema;
|
|
291
|
+
/**
|
|
292
|
+
* @public
|
|
293
|
+
*/
|
|
294
|
+
type ParameterSchema<Doc extends RequiredDoc, Schema extends ImmutableParameterObject['schema']> = ResolveDocParameterSchema<Doc, Schema> extends infer R ? R extends ImmutableSchemaObject ? R extends JSONSchema7 ? FromSchema<R> : never : never : never;
|
|
295
|
+
/**
|
|
296
|
+
* @public
|
|
297
|
+
*/
|
|
298
|
+
type MapToSchema<Doc extends RequiredDoc, T extends Record<string, ImmutableParameterObject>> = {
|
|
299
|
+
[V in keyof T]: NonNullable<T[V]> extends ImmutableParameterObject ? ParameterSchema<Doc, NonNullable<T[V]>['schema']> : never;
|
|
300
|
+
};
|
|
301
|
+
/**
|
|
302
|
+
* @public
|
|
303
|
+
*/
|
|
304
|
+
type ParametersSchema<Doc extends RequiredDoc, Path extends Extract<keyof Doc['paths'], string>, Method extends keyof Doc['paths'][Path], FilterType extends ImmutableParameterObject> = number extends keyof DocParameters<Doc, Path, Method> ? MapToSchema<Doc, FullMap<MapDiscriminatedUnion<Filter<DocParameters<Doc, Path, Method>[number], FilterType>, 'name'>>> : never;
|
|
305
|
+
/**
|
|
306
|
+
* @public
|
|
307
|
+
*/
|
|
308
|
+
type HeaderSchema<Doc extends RequiredDoc, Path extends PathTemplate<Extract<keyof Doc['paths'], string>>, Method extends DocPathMethod<Doc, Path>> = ParametersSchema<Doc, DocPath<Doc, Path>, Method, ImmutableHeaderObject>;
|
|
309
|
+
/**
|
|
310
|
+
* @public
|
|
311
|
+
*/
|
|
312
|
+
type CookieSchema<Doc extends RequiredDoc, Path extends PathTemplate<Extract<keyof Doc['paths'], string>>, Method extends DocPathMethod<Doc, Path>> = ParametersSchema<Doc, DocPath<Doc, Path>, Method, ImmutableCookieObject>;
|
|
313
|
+
/**
|
|
314
|
+
* @public
|
|
315
|
+
*/
|
|
316
|
+
type PathSchema<Doc extends RequiredDoc, Path extends PathTemplate<Extract<keyof Doc['paths'], string>>, Method extends DocPathMethod<Doc, Path>> = ParametersSchema<Doc, DocPath<Doc, Path>, Method, ImmutablePathObject>;
|
|
317
|
+
/**
|
|
318
|
+
* @public
|
|
319
|
+
*/
|
|
320
|
+
type QuerySchema<Doc extends RequiredDoc, Path extends PathTemplate<Extract<keyof Doc['paths'], string>>, Method extends DocPathMethod<Doc, Path>> = ParametersSchema<Doc, DocPath<Doc, Path>, Method, ImmutableQueryObject>;
|
|
321
|
+
|
|
322
|
+
/**
|
|
323
|
+
* Pulled from https://github.com/varanauskas/oatx.
|
|
324
|
+
*/
|
|
325
|
+
|
|
326
|
+
/**
|
|
327
|
+
* @public
|
|
328
|
+
*/
|
|
329
|
+
type RequestBody<Doc extends RequiredDoc, Path extends Extract<keyof Doc['paths'], string>, Method extends keyof Doc['paths'][Path]> = DocOperation<Doc, Path, Method>['requestBody'] extends ImmutableReferenceObject ? 'requestBodies' extends ComponentTypes<Doc> ? ComponentRef<Doc, 'requestBodies', DocOperation<Doc, Path, Method>['requestBody']> : never : DocOperation<Doc, Path, Method>['requestBody'];
|
|
330
|
+
/**
|
|
331
|
+
* @public
|
|
332
|
+
*/
|
|
333
|
+
type RequestBodySchema<Doc extends RequiredDoc, Path extends DocPathTemplate<Doc>, Method extends DocPathMethod<Doc, Path>> = RequestBody<Doc, DocPath<Doc, Path>, Method> extends ImmutableRequestBodyObject ? ObjectWithContentSchema<Doc, RequestBody<Doc, DocPath<Doc, Path>, Method>> : never;
|
|
334
|
+
/**
|
|
335
|
+
* Transform the OpenAPI request body schema to a typesafe JSON schema.
|
|
336
|
+
* @public
|
|
337
|
+
*/
|
|
338
|
+
type RequestBodyToJsonSchema<Doc extends RequiredDoc, Path extends PathTemplate<Extract<keyof Doc['paths'], string>>, Method extends DocPathMethod<Doc, Path>> = ToTypeSafe<RequestBodySchema<Doc, Path, Method>>;
|
|
339
|
+
|
|
340
|
+
/**
|
|
341
|
+
* Pulled from https://github.com/varanauskas/oatx.
|
|
342
|
+
*/
|
|
343
|
+
|
|
344
|
+
/**
|
|
345
|
+
* @public
|
|
346
|
+
*/
|
|
347
|
+
type Response<Doc extends RequiredDoc, Path extends keyof Doc['paths'], Method extends keyof Doc['paths'][Path], StatusCode extends keyof DocOperation<Doc, Path, Method>['responses']> = DocOperation<Doc, Path, Method>['responses'][StatusCode] extends ImmutableReferenceObject ? 'responses' extends ComponentTypes<Doc> ? ComponentRef<Doc, 'responses', DocOperation<Doc, Path, Method>['responses'][StatusCode]> : never : DocOperation<Doc, Path, Method>['responses'][StatusCode];
|
|
348
|
+
/**
|
|
349
|
+
* @public
|
|
350
|
+
*/
|
|
351
|
+
type ResponseSchemas<Doc extends RequiredDoc, Path extends DocPathTemplate<Doc>, Method extends DocPathMethod<Doc, Path>> = {
|
|
352
|
+
[StatusCode in keyof DocOperation<Doc, Path, Method>['responses']]: Response<Doc, Path, Method, StatusCode> extends ImmutableResponseObject ? ObjectWithContentSchema<Doc, Response<Doc, Path, Method, StatusCode>> : never;
|
|
353
|
+
};
|
|
354
|
+
/**
|
|
355
|
+
* Transform the OpenAPI request body schema to a typesafe JSON schema.
|
|
356
|
+
* @public
|
|
357
|
+
*/
|
|
358
|
+
type ResponseBodyToJsonSchema<Doc extends RequiredDoc, Path extends PathTemplate<Extract<keyof Doc['paths'], string>>, Method extends DocPathMethod<Doc, Path>> = ToTypeSafe<ValueOf<ResponseSchemas<Doc, Path, Method>>>;
|
|
359
|
+
|
|
360
|
+
/**
|
|
361
|
+
* Typed express request handler.
|
|
362
|
+
* @public
|
|
363
|
+
*/
|
|
364
|
+
type DocRequestHandler<Doc extends RequiredDoc, Path extends DocPathTemplate<Doc>, Method extends keyof Doc['paths'][Path]> = core.RequestHandler<PathSchema<Doc, Path, Method>, ResponseBodyToJsonSchema<Doc, Path, Method>, RequestBodyToJsonSchema<Doc, Path, Method>, QuerySchema<Doc, Path, Method>, Record<string, string>>;
|
|
365
|
+
/**
|
|
366
|
+
* Typed express error handler / request handler union type.
|
|
367
|
+
* @public
|
|
368
|
+
*/
|
|
369
|
+
type DocRequestHandlerParams<Doc extends RequiredDoc, Path extends DocPathTemplate<Doc>, Method extends keyof Doc['paths'][Path]> = core.RequestHandlerParams<PathSchema<Doc, Path, Method>, ResponseBodyToJsonSchema<Doc, Path, Method>, RequestBodyToJsonSchema<Doc, Path, Method>, QuerySchema<Doc, Path, Method>, Record<string, string>>;
|
|
370
|
+
/**
|
|
371
|
+
* Superset of the express router path matcher that enforces typed request and response bodies.
|
|
372
|
+
* @public
|
|
373
|
+
*/
|
|
374
|
+
interface DocRequestMatcher<Doc extends RequiredDoc, T, Method extends 'all' | 'get' | 'post' | 'put' | 'delete' | 'patch' | 'options' | 'head'> {
|
|
375
|
+
<Path extends MethodAwareDocPath<Doc, DocPathTemplate<Doc>, Method>>(path: Path, ...handlers: Array<DocRequestHandler<Doc, Path, Method>>): T;
|
|
376
|
+
<Path extends MethodAwareDocPath<Doc, DocPathTemplate<Doc>, Method>>(path: Path, ...handlers: Array<DocRequestHandlerParams<Doc, Path, Method>>): T;
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
type index_d_RequiredDoc = RequiredDoc;
|
|
380
|
+
type index_d_PathDoc = PathDoc;
|
|
381
|
+
type index_d_ValueOf<T> = ValueOf<T>;
|
|
382
|
+
type index_d_PathTemplate<Path extends string> = PathTemplate<Path>;
|
|
383
|
+
type index_d_DocPath<Doc extends PathDoc, Path extends PathTemplate<Extract<keyof Doc['paths'], string>>> = DocPath<Doc, Path>;
|
|
384
|
+
type index_d_DocPathTemplate<Doc extends PathDoc> = DocPathTemplate<Doc>;
|
|
385
|
+
type index_d_DocPathMethod<Doc extends Pick<RequiredDoc, 'paths'>, Path extends DocPathTemplate<Doc>> = DocPathMethod<Doc, Path>;
|
|
386
|
+
type index_d_MethodAwareDocPath<Doc extends PathDoc, Path extends PathTemplate<Extract<keyof Doc['paths'], string>>, Method extends keyof Doc['paths'][Path]> = MethodAwareDocPath<Doc, Path, Method>;
|
|
387
|
+
type index_d_DocOperation<Doc extends RequiredDoc, Path extends keyof Doc['paths'], Method extends keyof Doc['paths'][Path]> = DocOperation<Doc, Path, Method>;
|
|
388
|
+
type index_d_ComponentTypes<Doc extends RequiredDoc> = ComponentTypes<Doc>;
|
|
389
|
+
type index_d_ComponentRef<Doc extends RequiredDoc, Type extends ComponentTypes<Doc>, Ref extends ImmutableReferenceObject> = ComponentRef<Doc, Type, Ref>;
|
|
390
|
+
type index_d_SchemaRef<Doc extends RequiredDoc, Schema> = SchemaRef<Doc, Schema>;
|
|
391
|
+
type index_d_ObjectWithContentSchema<Doc extends RequiredDoc, Object extends {
|
|
392
|
+
content?: ImmutableContentObject;
|
|
393
|
+
}> = ObjectWithContentSchema<Doc, Object>;
|
|
394
|
+
type index_d_UnionToIntersection<U> = UnionToIntersection<U>;
|
|
395
|
+
type index_d_LastOf<T> = LastOf<T>;
|
|
396
|
+
type index_d_Push<T extends any[], V> = Push<T, V>;
|
|
397
|
+
type index_d_TuplifyUnion<T, L = LastOf<T>, N = [T] extends [never] ? true : false> = TuplifyUnion<T, L, N>;
|
|
398
|
+
type index_d_ConvertAll<T, R extends ReadonlyArray<unknown> = []> = ConvertAll<T, R>;
|
|
399
|
+
type index_d_UnknownIfNever<P> = UnknownIfNever<P>;
|
|
400
|
+
type index_d_ToTypeSafe<T> = ToTypeSafe<T>;
|
|
401
|
+
type index_d_DiscriminateUnion<T, K extends keyof T, V extends T[K]> = DiscriminateUnion<T, K, V>;
|
|
402
|
+
type index_d_MapDiscriminatedUnion<T extends Record<K, string>, K extends keyof T> = MapDiscriminatedUnion<T, K>;
|
|
403
|
+
type index_d_PickOptionalKeys<T extends {
|
|
404
|
+
[key: string]: any;
|
|
405
|
+
}> = PickOptionalKeys<T>;
|
|
406
|
+
type index_d_PickRequiredKeys<T extends {
|
|
407
|
+
[key: string]: any;
|
|
408
|
+
}> = PickRequiredKeys<T>;
|
|
409
|
+
type index_d_OptionalMap<T extends {
|
|
410
|
+
[key: string]: any;
|
|
411
|
+
}> = OptionalMap<T>;
|
|
412
|
+
type index_d_RequiredMap<T extends {
|
|
413
|
+
[key: string]: any;
|
|
414
|
+
}> = RequiredMap<T>;
|
|
415
|
+
type index_d_FullMap<T extends {
|
|
416
|
+
[key: string]: any;
|
|
417
|
+
}> = FullMap<T>;
|
|
418
|
+
type index_d_Filter<T, U> = Filter<T, U>;
|
|
419
|
+
type index_d_DocRequestHandler<Doc extends RequiredDoc, Path extends DocPathTemplate<Doc>, Method extends keyof Doc['paths'][Path]> = DocRequestHandler<Doc, Path, Method>;
|
|
420
|
+
type index_d_DocRequestHandlerParams<Doc extends RequiredDoc, Path extends DocPathTemplate<Doc>, Method extends keyof Doc['paths'][Path]> = DocRequestHandlerParams<Doc, Path, Method>;
|
|
421
|
+
type index_d_DocRequestMatcher<Doc extends RequiredDoc, T, Method extends 'all' | 'get' | 'post' | 'put' | 'delete' | 'patch' | 'options' | 'head'> = DocRequestMatcher<Doc, T, Method>;
|
|
422
|
+
type index_d_Immutable<T> = Immutable<T>;
|
|
423
|
+
type index_d_ImmutableObject<T> = ImmutableObject<T>;
|
|
424
|
+
type index_d_ImmutableReferenceObject = ImmutableReferenceObject;
|
|
425
|
+
type index_d_ImmutableOpenAPIObject = ImmutableOpenAPIObject;
|
|
426
|
+
type index_d_ImmutableContentObject = ImmutableContentObject;
|
|
427
|
+
type index_d_ImmutableRequestBodyObject = ImmutableRequestBodyObject;
|
|
428
|
+
type index_d_ImmutableResponseObject = ImmutableResponseObject;
|
|
429
|
+
type index_d_ImmutableParameterObject = ImmutableParameterObject;
|
|
430
|
+
type index_d_HeaderObject = HeaderObject;
|
|
431
|
+
type index_d_ImmutableHeaderObject = ImmutableHeaderObject;
|
|
432
|
+
type index_d_CookieObject = CookieObject;
|
|
433
|
+
type index_d_ImmutableCookieObject = ImmutableCookieObject;
|
|
434
|
+
type index_d_QueryObject = QueryObject;
|
|
435
|
+
type index_d_ImmutableQueryObject = ImmutableQueryObject;
|
|
436
|
+
type index_d_PathObject = PathObject;
|
|
437
|
+
type index_d_ImmutablePathObject = ImmutablePathObject;
|
|
438
|
+
type index_d_ImmutableSchemaObject = ImmutableSchemaObject;
|
|
439
|
+
type index_d_DocParameter<Doc extends RequiredDoc, Path extends Extract<keyof Doc['paths'], string>, Method extends keyof Doc['paths'][Path], Parameter extends keyof Doc['paths'][Path][Method]['parameters']> = DocParameter<Doc, Path, Method, Parameter>;
|
|
440
|
+
type index_d_DocParameters<Doc extends RequiredDoc, Path extends Extract<keyof Doc['paths'], string>, Method extends keyof Doc['paths'][Path]> = DocParameters<Doc, Path, Method>;
|
|
441
|
+
type index_d_ResolveDocParameterSchema<Doc extends RequiredDoc, Schema extends ImmutableParameterObject['schema']> = ResolveDocParameterSchema<Doc, Schema>;
|
|
442
|
+
type index_d_ParameterSchema<Doc extends RequiredDoc, Schema extends ImmutableParameterObject['schema']> = ParameterSchema<Doc, Schema>;
|
|
443
|
+
type index_d_MapToSchema<Doc extends RequiredDoc, T extends Record<string, ImmutableParameterObject>> = MapToSchema<Doc, T>;
|
|
444
|
+
type index_d_ParametersSchema<Doc extends RequiredDoc, Path extends Extract<keyof Doc['paths'], string>, Method extends keyof Doc['paths'][Path], FilterType extends ImmutableParameterObject> = ParametersSchema<Doc, Path, Method, FilterType>;
|
|
445
|
+
type index_d_HeaderSchema<Doc extends RequiredDoc, Path extends PathTemplate<Extract<keyof Doc['paths'], string>>, Method extends DocPathMethod<Doc, Path>> = HeaderSchema<Doc, Path, Method>;
|
|
446
|
+
type index_d_CookieSchema<Doc extends RequiredDoc, Path extends PathTemplate<Extract<keyof Doc['paths'], string>>, Method extends DocPathMethod<Doc, Path>> = CookieSchema<Doc, Path, Method>;
|
|
447
|
+
type index_d_PathSchema<Doc extends RequiredDoc, Path extends PathTemplate<Extract<keyof Doc['paths'], string>>, Method extends DocPathMethod<Doc, Path>> = PathSchema<Doc, Path, Method>;
|
|
448
|
+
type index_d_QuerySchema<Doc extends RequiredDoc, Path extends PathTemplate<Extract<keyof Doc['paths'], string>>, Method extends DocPathMethod<Doc, Path>> = QuerySchema<Doc, Path, Method>;
|
|
449
|
+
type index_d_RequestBody<Doc extends RequiredDoc, Path extends Extract<keyof Doc['paths'], string>, Method extends keyof Doc['paths'][Path]> = RequestBody<Doc, Path, Method>;
|
|
450
|
+
type index_d_RequestBodySchema<Doc extends RequiredDoc, Path extends DocPathTemplate<Doc>, Method extends DocPathMethod<Doc, Path>> = RequestBodySchema<Doc, Path, Method>;
|
|
451
|
+
type index_d_RequestBodyToJsonSchema<Doc extends RequiredDoc, Path extends PathTemplate<Extract<keyof Doc['paths'], string>>, Method extends DocPathMethod<Doc, Path>> = RequestBodyToJsonSchema<Doc, Path, Method>;
|
|
452
|
+
type index_d_Response<Doc extends RequiredDoc, Path extends keyof Doc['paths'], Method extends keyof Doc['paths'][Path], StatusCode extends keyof DocOperation<Doc, Path, Method>['responses']> = Response<Doc, Path, Method, StatusCode>;
|
|
453
|
+
type index_d_ResponseSchemas<Doc extends RequiredDoc, Path extends DocPathTemplate<Doc>, Method extends DocPathMethod<Doc, Path>> = ResponseSchemas<Doc, Path, Method>;
|
|
454
|
+
type index_d_ResponseBodyToJsonSchema<Doc extends RequiredDoc, Path extends PathTemplate<Extract<keyof Doc['paths'], string>>, Method extends DocPathMethod<Doc, Path>> = ResponseBodyToJsonSchema<Doc, Path, Method>;
|
|
455
|
+
declare namespace index_d {
|
|
456
|
+
export {
|
|
457
|
+
index_d_RequiredDoc as RequiredDoc,
|
|
458
|
+
index_d_PathDoc as PathDoc,
|
|
459
|
+
index_d_ValueOf as ValueOf,
|
|
460
|
+
index_d_PathTemplate as PathTemplate,
|
|
461
|
+
index_d_DocPath as DocPath,
|
|
462
|
+
index_d_DocPathTemplate as DocPathTemplate,
|
|
463
|
+
index_d_DocPathMethod as DocPathMethod,
|
|
464
|
+
index_d_MethodAwareDocPath as MethodAwareDocPath,
|
|
465
|
+
index_d_DocOperation as DocOperation,
|
|
466
|
+
index_d_ComponentTypes as ComponentTypes,
|
|
467
|
+
index_d_ComponentRef as ComponentRef,
|
|
468
|
+
index_d_SchemaRef as SchemaRef,
|
|
469
|
+
index_d_ObjectWithContentSchema as ObjectWithContentSchema,
|
|
470
|
+
index_d_UnionToIntersection as UnionToIntersection,
|
|
471
|
+
index_d_LastOf as LastOf,
|
|
472
|
+
index_d_Push as Push,
|
|
473
|
+
index_d_TuplifyUnion as TuplifyUnion,
|
|
474
|
+
index_d_ConvertAll as ConvertAll,
|
|
475
|
+
index_d_UnknownIfNever as UnknownIfNever,
|
|
476
|
+
index_d_ToTypeSafe as ToTypeSafe,
|
|
477
|
+
index_d_DiscriminateUnion as DiscriminateUnion,
|
|
478
|
+
index_d_MapDiscriminatedUnion as MapDiscriminatedUnion,
|
|
479
|
+
index_d_PickOptionalKeys as PickOptionalKeys,
|
|
480
|
+
index_d_PickRequiredKeys as PickRequiredKeys,
|
|
481
|
+
index_d_OptionalMap as OptionalMap,
|
|
482
|
+
index_d_RequiredMap as RequiredMap,
|
|
483
|
+
index_d_FullMap as FullMap,
|
|
484
|
+
index_d_Filter as Filter,
|
|
485
|
+
index_d_DocRequestHandler as DocRequestHandler,
|
|
486
|
+
index_d_DocRequestHandlerParams as DocRequestHandlerParams,
|
|
487
|
+
index_d_DocRequestMatcher as DocRequestMatcher,
|
|
488
|
+
index_d_Immutable as Immutable,
|
|
489
|
+
index_d_ImmutableObject as ImmutableObject,
|
|
490
|
+
index_d_ImmutableReferenceObject as ImmutableReferenceObject,
|
|
491
|
+
index_d_ImmutableOpenAPIObject as ImmutableOpenAPIObject,
|
|
492
|
+
index_d_ImmutableContentObject as ImmutableContentObject,
|
|
493
|
+
index_d_ImmutableRequestBodyObject as ImmutableRequestBodyObject,
|
|
494
|
+
index_d_ImmutableResponseObject as ImmutableResponseObject,
|
|
495
|
+
index_d_ImmutableParameterObject as ImmutableParameterObject,
|
|
496
|
+
index_d_HeaderObject as HeaderObject,
|
|
497
|
+
index_d_ImmutableHeaderObject as ImmutableHeaderObject,
|
|
498
|
+
index_d_CookieObject as CookieObject,
|
|
499
|
+
index_d_ImmutableCookieObject as ImmutableCookieObject,
|
|
500
|
+
index_d_QueryObject as QueryObject,
|
|
501
|
+
index_d_ImmutableQueryObject as ImmutableQueryObject,
|
|
502
|
+
index_d_PathObject as PathObject,
|
|
503
|
+
index_d_ImmutablePathObject as ImmutablePathObject,
|
|
504
|
+
index_d_ImmutableSchemaObject as ImmutableSchemaObject,
|
|
505
|
+
index_d_DocParameter as DocParameter,
|
|
506
|
+
index_d_DocParameters as DocParameters,
|
|
507
|
+
index_d_ResolveDocParameterSchema as ResolveDocParameterSchema,
|
|
508
|
+
index_d_ParameterSchema as ParameterSchema,
|
|
509
|
+
index_d_MapToSchema as MapToSchema,
|
|
510
|
+
index_d_ParametersSchema as ParametersSchema,
|
|
511
|
+
index_d_HeaderSchema as HeaderSchema,
|
|
512
|
+
index_d_CookieSchema as CookieSchema,
|
|
513
|
+
index_d_PathSchema as PathSchema,
|
|
514
|
+
index_d_QuerySchema as QuerySchema,
|
|
515
|
+
index_d_RequestBody as RequestBody,
|
|
516
|
+
index_d_RequestBodySchema as RequestBodySchema,
|
|
517
|
+
index_d_RequestBodyToJsonSchema as RequestBodyToJsonSchema,
|
|
518
|
+
index_d_Response as Response,
|
|
519
|
+
index_d_ResponseSchemas as ResponseSchemas,
|
|
520
|
+
index_d_ResponseBodyToJsonSchema as ResponseBodyToJsonSchema,
|
|
521
|
+
};
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
/**
|
|
525
|
+
* Typed Express router based on an OpenAPI 3.1 spec.
|
|
526
|
+
* @public
|
|
527
|
+
*/
|
|
528
|
+
interface ApiRouter<Doc extends RequiredDoc> extends Router {
|
|
529
|
+
get: DocRequestMatcher<Doc, this, 'get'>;
|
|
530
|
+
post: DocRequestMatcher<Doc, this, 'post'>;
|
|
531
|
+
all: DocRequestMatcher<Doc, this, 'all'>;
|
|
532
|
+
put: DocRequestMatcher<Doc, this, 'put'>;
|
|
533
|
+
delete: DocRequestMatcher<Doc, this, 'delete'>;
|
|
534
|
+
patch: DocRequestMatcher<Doc, this, 'patch'>;
|
|
535
|
+
options: DocRequestMatcher<Doc, this, 'options'>;
|
|
536
|
+
head: DocRequestMatcher<Doc, this, 'head'>;
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
export { ApiRouter, index_d as internal };
|
package/package.json
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@backstage/backend-openapi-utils",
|
|
3
|
+
"description": "OpenAPI typescript support.",
|
|
4
|
+
"version": "0.0.0-nightly-20230407021743",
|
|
5
|
+
"main": "dist/index.cjs.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"license": "Apache-2.0",
|
|
8
|
+
"publishConfig": {
|
|
9
|
+
"access": "public",
|
|
10
|
+
"main": "dist/index.cjs.js",
|
|
11
|
+
"module": "dist/index.esm.js",
|
|
12
|
+
"types": "dist/index.d.ts"
|
|
13
|
+
},
|
|
14
|
+
"backstage": {
|
|
15
|
+
"role": "node-library"
|
|
16
|
+
},
|
|
17
|
+
"scripts": {
|
|
18
|
+
"start": "backstage-cli package start",
|
|
19
|
+
"build": "backstage-cli package build",
|
|
20
|
+
"lint": "backstage-cli package lint",
|
|
21
|
+
"test": "backstage-cli package test",
|
|
22
|
+
"clean": "backstage-cli package clean",
|
|
23
|
+
"prepack": "backstage-cli package prepack",
|
|
24
|
+
"postpack": "backstage-cli package postpack"
|
|
25
|
+
},
|
|
26
|
+
"devDependencies": {
|
|
27
|
+
"@backstage/cli": "^0.0.0-nightly-20230407021743"
|
|
28
|
+
},
|
|
29
|
+
"files": [
|
|
30
|
+
"dist"
|
|
31
|
+
],
|
|
32
|
+
"dependencies": {
|
|
33
|
+
"@types/express": "^4.17.6",
|
|
34
|
+
"@types/express-serve-static-core": "^4.17.5",
|
|
35
|
+
"express": "^4.17.1",
|
|
36
|
+
"express-promise-router": "^4.1.0",
|
|
37
|
+
"json-schema-to-ts": "^2.6.2",
|
|
38
|
+
"openapi3-ts": "^3.1.2"
|
|
39
|
+
},
|
|
40
|
+
"module": "dist/index.esm.js"
|
|
41
|
+
}
|