it works!
Signed-off-by: aramissennyeydd <aramis.sennyey@doordash.com> Signed-off-by: Aramis Sennyey <159921952+aramissennyeydd@users.noreply.github.com> Signed-off-by: aramissennyeydd <aramis.sennyey@doordash.com>
This commit is contained in:
@@ -36,5 +36,9 @@ export type {
|
||||
RequestMatcherByModelAndPathParams,
|
||||
} from './types/express';
|
||||
export type { PathTemplate } from './types/common';
|
||||
export { createValidatedOpenApiRouter, getOpenApiSpecRoute } from './stub';
|
||||
export { wrapInOpenApiTestServer, wrapServer } from './testUtils';
|
||||
export {
|
||||
createValidatedOpenApiRouter,
|
||||
getOpenApiSpecRoute,
|
||||
createValidatedOpenApiRouterFromGeneratedEndpointMap,
|
||||
} from './stub';
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
import PromiseRouter from 'express-promise-router';
|
||||
import { ApiRouter } from './router';
|
||||
import { RequiredDoc } from './types';
|
||||
import { EndpointMap, RequiredDoc, TypedRouter } from './types';
|
||||
import {
|
||||
ErrorRequestHandler,
|
||||
RequestHandler,
|
||||
@@ -24,6 +24,7 @@ import {
|
||||
Request,
|
||||
Response,
|
||||
json,
|
||||
Router,
|
||||
} from 'express';
|
||||
import { InputError } from '@backstage/errors';
|
||||
import { middleware as OpenApiValidator } from 'express-openapi-validator';
|
||||
@@ -58,19 +59,19 @@ export function getOpenApiSpecRoute(baseUrl: string) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new OpenAPI router with some default middleware.
|
||||
* Create a router with validation middleware. This is used by typing methods to create an
|
||||
* "OpenAPI router" with all of the expected validation + metadata.
|
||||
* @param spec - Your OpenAPI spec imported as a JSON object.
|
||||
* @param validatorOptions - `openapi-express-validator` options to override the defaults.
|
||||
* @returns A new express router with validation middleware.
|
||||
* @public
|
||||
*/
|
||||
export function createValidatedOpenApiRouter<T extends RequiredDoc>(
|
||||
spec: T,
|
||||
function createRouterWithValidation(
|
||||
spec: RequiredDoc,
|
||||
options?: {
|
||||
validatorOptions?: Partial<Parameters<typeof OpenApiValidator>['0']>;
|
||||
middleware?: RequestHandler[];
|
||||
},
|
||||
) {
|
||||
): Router {
|
||||
const router = PromiseRouter();
|
||||
router.use(options?.middleware || getDefaultRouterMiddleware());
|
||||
|
||||
@@ -152,6 +153,41 @@ export function createValidatedOpenApiRouter<T extends RequiredDoc>(
|
||||
}
|
||||
res.json(mergeOutput.output);
|
||||
});
|
||||
|
||||
return router as ApiRouter<typeof spec>;
|
||||
return router;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new OpenAPI router with some default middleware.
|
||||
* @param spec - Your OpenAPI spec imported as a JSON object.
|
||||
* @param validatorOptions - `openapi-express-validator` options to override the defaults.
|
||||
* @returns A new express router with validation middleware.
|
||||
* @public
|
||||
*/
|
||||
export function createValidatedOpenApiRouter<T extends RequiredDoc>(
|
||||
spec: T,
|
||||
options?: {
|
||||
validatorOptions?: Partial<Parameters<typeof OpenApiValidator>['0']>;
|
||||
middleware?: RequestHandler[];
|
||||
},
|
||||
) {
|
||||
return createRouterWithValidation(spec, options) as ApiRouter<typeof spec>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new OpenAPI router with some default middleware.
|
||||
* @param spec - Your OpenAPI spec imported as a JSON object.
|
||||
* @param validatorOptions - `openapi-express-validator` options to override the defaults.
|
||||
* @returns A new express router with validation middleware.
|
||||
* @public
|
||||
*/
|
||||
export function createValidatedOpenApiRouterFromGeneratedEndpointMap<
|
||||
T extends EndpointMap,
|
||||
>(
|
||||
spec: RequiredDoc,
|
||||
options?: {
|
||||
validatorOptions?: Partial<Parameters<typeof OpenApiValidator>['0']>;
|
||||
middleware?: RequestHandler[];
|
||||
},
|
||||
) {
|
||||
return createRouterWithValidation(spec, options) as TypedRouter<T>;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,188 @@
|
||||
/*
|
||||
* Copyright 2024 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { Router } from 'express';
|
||||
import type core from 'express-serve-static-core';
|
||||
import { PathTemplate, ValueOf } from './common';
|
||||
|
||||
export type EndpointMap = Record<
|
||||
string,
|
||||
{ query?: object; body?: object; response: object | void; path?: object }
|
||||
>;
|
||||
|
||||
type UnknownIfVoid<T> = T extends void ? unknown : T;
|
||||
|
||||
// OpenAPI generator doesn't emit regular lowercase 'delete'.
|
||||
type HttpMethods = 'all' | 'put' | 'get' | 'post' | '_delete';
|
||||
|
||||
type PathSchema<
|
||||
Doc extends EndpointMap,
|
||||
Endpoint extends DocEndpoint<Doc>,
|
||||
Method extends DocEndpointMethod<Doc, Endpoint>,
|
||||
> = `#${Method}|${Endpoint}` extends keyof Doc
|
||||
? 'path' extends keyof Doc[`#${Method}|${Endpoint}`]
|
||||
? Doc[`#${Method}|${Endpoint}`]['path']
|
||||
: never
|
||||
: never;
|
||||
type RequestBody<
|
||||
Doc extends EndpointMap,
|
||||
Endpoint extends DocEndpoint<Doc>,
|
||||
Method extends DocEndpointMethod<Doc, Endpoint>,
|
||||
> = `#${Method}|${Endpoint}` extends keyof Doc
|
||||
? 'body' extends keyof Doc[`#${Method}|${Endpoint}`]
|
||||
? Doc[`#${Method}|${Endpoint}`]['body']
|
||||
: unknown
|
||||
: unknown;
|
||||
type ResponseBody<
|
||||
Doc extends EndpointMap,
|
||||
Endpoint extends DocEndpoint<Doc>,
|
||||
Method extends DocEndpointMethod<Doc, Endpoint>,
|
||||
> = `#${Method}|${Endpoint}` extends keyof Doc
|
||||
? 'response' extends keyof Doc[`#${Method}|${Endpoint}`]
|
||||
? UnknownIfVoid<Doc[`#${Method}|${Endpoint}`]['response']>
|
||||
: unknown
|
||||
: unknown;
|
||||
type QuerySchema<
|
||||
Doc extends EndpointMap,
|
||||
Endpoint extends DocEndpoint<Doc>,
|
||||
Method extends DocEndpointMethod<Doc, Endpoint>,
|
||||
> = `#${Method}|${Endpoint}` extends keyof Doc
|
||||
? 'query' extends keyof Doc[`#${Method}|${Endpoint}`]
|
||||
? Doc[`#${Method}|${Endpoint}`]['query']
|
||||
: never
|
||||
: never;
|
||||
|
||||
/**
|
||||
* Typed express request handler.
|
||||
* @public
|
||||
*/
|
||||
export type EndpointMapRequestHandler<
|
||||
Doc extends EndpointMap,
|
||||
Path extends DocEndpoint<Doc>,
|
||||
Method extends DocEndpointMethod<Doc, Path>,
|
||||
> = core.RequestHandler<
|
||||
PathSchema<Doc, Path, Method>,
|
||||
ResponseBody<Doc, Path, Method>,
|
||||
RequestBody<Doc, Path, Method>,
|
||||
QuerySchema<Doc, Path, Method>,
|
||||
Record<string, string>
|
||||
>;
|
||||
|
||||
/**
|
||||
* Typed express error handler / request handler union type.
|
||||
* @public
|
||||
*/
|
||||
export type EndpointMapRequestHandlerParams<
|
||||
Doc extends EndpointMap,
|
||||
Path extends DocEndpoint<Doc>,
|
||||
Method extends DocEndpointMethod<Doc, Path>,
|
||||
> = core.RequestHandlerParams<
|
||||
PathSchema<Doc, Path, Method>,
|
||||
ResponseBody<Doc, Path, Method>,
|
||||
RequestBody<Doc, Path, Method>,
|
||||
QuerySchema<Doc, Path, Method>,
|
||||
Record<string, string>
|
||||
>;
|
||||
|
||||
type DocEndpoint<Doc extends EndpointMap> = ValueOf<{
|
||||
[Template in keyof Doc]: Template extends `#${string}|${infer Endpoint}`
|
||||
? Endpoint
|
||||
: never;
|
||||
}>;
|
||||
|
||||
type DocEndpointMethod<
|
||||
Doc extends EndpointMap,
|
||||
Endpoint extends DocEndpoint<Doc>,
|
||||
> = ValueOf<{
|
||||
[Template in keyof Doc]: Template extends `#${infer Method}|${Endpoint}`
|
||||
? Method
|
||||
: never;
|
||||
}>;
|
||||
|
||||
type MethodAwareDocEndpoints<
|
||||
Doc extends EndpointMap,
|
||||
Endpoint extends DocEndpoint<Doc>,
|
||||
Method extends DocEndpointMethod<Doc, Endpoint>,
|
||||
> = ValueOf<{
|
||||
[Template in keyof Doc]: Template extends `#${Method}|${infer E}`
|
||||
? E extends DocEndpoint<Doc>
|
||||
? PathTemplate<E>
|
||||
: never
|
||||
: never;
|
||||
}>;
|
||||
|
||||
type DocEndpointTemplate<Doc extends EndpointMap> = PathTemplate<
|
||||
DocEndpoint<Doc>
|
||||
>;
|
||||
|
||||
export type TemplateToDocEndpoint<
|
||||
Doc extends EndpointMap,
|
||||
Path extends DocEndpointTemplate<Doc>,
|
||||
> = ValueOf<{
|
||||
[Template in DocEndpoint<Doc>]: Path extends PathTemplate<Template>
|
||||
? Template
|
||||
: never;
|
||||
}>;
|
||||
|
||||
/**
|
||||
* Superset of the express router path matcher that enforces typed request and response bodies.
|
||||
* @public
|
||||
*/
|
||||
export interface EndpointMapRequestMatcher<
|
||||
Doc extends EndpointMap,
|
||||
T,
|
||||
Method extends HttpMethods,
|
||||
> {
|
||||
<
|
||||
TPath extends MethodAwareDocEndpoints<
|
||||
Doc,
|
||||
DocEndpoint<Doc>,
|
||||
Method & DocEndpointMethod<Doc, DocEndpoint<Doc>>
|
||||
>,
|
||||
TMethod extends Method &
|
||||
DocEndpointMethod<Doc, TemplateToDocEndpoint<Doc, TPath>>,
|
||||
>(
|
||||
path: TPath,
|
||||
...handlers: Array<
|
||||
EndpointMapRequestHandler<Doc, TemplateToDocEndpoint<Doc, TPath>, TMethod>
|
||||
>
|
||||
): T;
|
||||
<
|
||||
TPath extends MethodAwareDocEndpoints<
|
||||
Doc,
|
||||
DocEndpoint<Doc>,
|
||||
Method & DocEndpointMethod<Doc, DocEndpoint<Doc>>
|
||||
>,
|
||||
TMethod extends Method &
|
||||
DocEndpointMethod<Doc, TemplateToDocEndpoint<Doc, TPath>>,
|
||||
>(
|
||||
path: TPath,
|
||||
...handlers: Array<
|
||||
EndpointMapRequestHandlerParams<
|
||||
Doc,
|
||||
TemplateToDocEndpoint<Doc, TPath>,
|
||||
TMethod
|
||||
>
|
||||
>
|
||||
): T;
|
||||
}
|
||||
|
||||
export interface TypedRouter<GeneratedEndpointMap extends EndpointMap>
|
||||
extends Router {
|
||||
get: EndpointMapRequestMatcher<GeneratedEndpointMap, this, 'get'>;
|
||||
post: EndpointMapRequestMatcher<GeneratedEndpointMap, this, 'post'>;
|
||||
put: EndpointMapRequestMatcher<GeneratedEndpointMap, this, 'put'>;
|
||||
delete: EndpointMapRequestMatcher<GeneratedEndpointMap, this, '_delete'>;
|
||||
}
|
||||
@@ -20,3 +20,4 @@ export * from './immutable';
|
||||
export * from './params';
|
||||
export * from './requests';
|
||||
export * from './responses';
|
||||
export * from './generated';
|
||||
|
||||
@@ -23,7 +23,7 @@ import { EntityRelation } from '../models/EntityRelation.model';
|
||||
/**
|
||||
* The parts of the format that's common to all versions/kinds of entity.
|
||||
*/
|
||||
export interface NullableEntity {
|
||||
export type NullableEntity = {
|
||||
/**
|
||||
* The relations that this entity has with other entities.
|
||||
*/
|
||||
@@ -41,4 +41,4 @@ export interface NullableEntity {
|
||||
* The version of specification format for this particular entity that this is written against.
|
||||
*/
|
||||
apiVersion: string;
|
||||
}
|
||||
} | null;
|
||||
|
||||
@@ -1,101 +0,0 @@
|
||||
/*
|
||||
* Copyright 2023 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import chalk from 'chalk';
|
||||
import { resolve } from 'path';
|
||||
import { OPENAPI_IGNORE_FILES, OUTPUT_PATH } from '../constants';
|
||||
import { paths as cliPaths } from '../../../lib/paths';
|
||||
import { mkdirpSync } from 'fs-extra';
|
||||
import fs from 'fs-extra';
|
||||
import { exec } from '../../../lib/exec';
|
||||
import { resolvePackagePath } from '@backstage/backend-common';
|
||||
|
||||
async function generate(spec: string, outputDirectory: string) {
|
||||
const resolvedOpenapiPath = resolve(spec);
|
||||
const resolvedOutputDirectory = resolve(outputDirectory, OUTPUT_PATH);
|
||||
mkdirpSync(resolvedOutputDirectory);
|
||||
|
||||
await fs.mkdirp(resolvedOutputDirectory);
|
||||
|
||||
await fs.writeFile(
|
||||
resolve(resolvedOutputDirectory, '.openapi-generator-ignore'),
|
||||
OPENAPI_IGNORE_FILES.join('\n'),
|
||||
);
|
||||
|
||||
await exec(
|
||||
'node',
|
||||
[
|
||||
resolvePackagePath('@openapitools/openapi-generator-cli', 'main.js'),
|
||||
'generate',
|
||||
'-i',
|
||||
resolvedOpenapiPath,
|
||||
'-o',
|
||||
resolvedOutputDirectory,
|
||||
'-g',
|
||||
'typescript',
|
||||
'-c',
|
||||
resolvePackagePath(
|
||||
'@backstage/repo-tools',
|
||||
'templates/typescript-backstage.server.yaml',
|
||||
),
|
||||
`--additional-properties=clientPackageName=@backstage/catalog-client`,
|
||||
'--generator-key',
|
||||
'v3.0',
|
||||
],
|
||||
{
|
||||
maxBuffer: Number.MAX_VALUE,
|
||||
cwd: resolvePackagePath('@backstage/repo-tools'),
|
||||
env: {
|
||||
...process.env,
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
await exec(
|
||||
`yarn backstage-cli package lint --fix ${resolvedOutputDirectory}`,
|
||||
);
|
||||
|
||||
const prettier = cliPaths.resolveTargetRoot('node_modules/.bin/prettier');
|
||||
if (prettier) {
|
||||
await exec(`${prettier} --write ${resolvedOutputDirectory}`);
|
||||
}
|
||||
|
||||
fs.removeSync(resolve(resolvedOutputDirectory, '.openapi-generator-ignore'));
|
||||
|
||||
fs.rmSync(resolve(resolvedOutputDirectory, '.openapi-generator'), {
|
||||
recursive: true,
|
||||
force: true,
|
||||
});
|
||||
}
|
||||
|
||||
export async function singleCommand({
|
||||
inputSpec,
|
||||
outputDirectory,
|
||||
}: {
|
||||
inputSpec: string;
|
||||
outputDirectory: string;
|
||||
}): Promise<void> {
|
||||
try {
|
||||
await generate(inputSpec, outputDirectory);
|
||||
console.log(chalk.green(`Generated client for ${inputSpec}`));
|
||||
} catch (err) {
|
||||
console.log();
|
||||
console.log(chalk.red(`Client generation failed in ${outputDirectory}:`));
|
||||
console.log(err);
|
||||
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
@@ -16,9 +16,11 @@
|
||||
|
||||
import chalk from 'chalk';
|
||||
import { resolve } from 'path';
|
||||
import YAML from 'js-yaml';
|
||||
import {
|
||||
OPENAPI_IGNORE_FILES,
|
||||
OUTPUT_PATH,
|
||||
TS_SCHEMA_PATH,
|
||||
} from '../../../../../lib/openapi/constants';
|
||||
import { paths as cliPaths } from '../../../../../lib/paths';
|
||||
import { mkdirpSync } from 'fs-extra';
|
||||
@@ -30,6 +32,40 @@ import {
|
||||
getRelativePathToFile,
|
||||
} from '../../../../../lib/openapi/helpers';
|
||||
|
||||
async function generateSpecFile() {
|
||||
const openapiPath = await getPathToCurrentOpenApiSpec();
|
||||
const yaml = YAML.load(await fs.readFile(openapiPath, 'utf8'));
|
||||
|
||||
const tsPath = cliPaths.resolveTarget(TS_SCHEMA_PATH);
|
||||
|
||||
// The first set of comment slashes allow for the eslint notice plugin to run
|
||||
// with onNonMatchingHeader: 'replace', as is the case in the open source
|
||||
// Backstage repo. Otherwise the auto-generated comment will be removed by the
|
||||
// lint call below.
|
||||
await fs.writeFile(
|
||||
tsPath,
|
||||
`//
|
||||
|
||||
// ******************************************************************
|
||||
// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. *
|
||||
// ******************************************************************
|
||||
import {createValidatedOpenApiRouterFromGeneratedEndpointMap} from '@backstage/backend-openapi-utils';
|
||||
import {EndpointMap} from '../generated';
|
||||
export const spec = ${JSON.stringify(yaml, null, 2)} as const;
|
||||
export const createOpenApiRouter = async (
|
||||
options?: Parameters<typeof createValidatedOpenApiRouterFromGeneratedEndpointMap>['1'],
|
||||
) => createValidatedOpenApiRouterFromGeneratedEndpointMap<EndpointMap>(spec, options);
|
||||
`,
|
||||
);
|
||||
|
||||
await exec(`yarn backstage-cli package lint --fix ${tsPath}`);
|
||||
if (await cliPaths.resolveTargetRoot('node_modules/.bin/prettier')) {
|
||||
await exec(`yarn prettier`, ['--write', tsPath], {
|
||||
cwd: cliPaths.targetRoot,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async function generate(abortSignal?: AbortController) {
|
||||
const resolvedOpenapiPath = await getPathToCurrentOpenApiSpec();
|
||||
const resolvedOutputDirectory = await getRelativePathToFile(OUTPUT_PATH);
|
||||
@@ -93,6 +129,8 @@ async function generate(abortSignal?: AbortController) {
|
||||
recursive: true,
|
||||
force: true,
|
||||
});
|
||||
|
||||
await generateSpecFile();
|
||||
}
|
||||
|
||||
export async function command({
|
||||
|
||||
@@ -35,3 +35,6 @@ files:
|
||||
client/pluginId.mustache:
|
||||
templateType: SupportingFiles
|
||||
destinationFilename: pluginId.ts
|
||||
client/index.mustache:
|
||||
templateType: SupportingFiles
|
||||
destinationFilename: index.ts
|
||||
|
||||
@@ -5,6 +5,9 @@ files:
|
||||
templateType: API
|
||||
# For some reason, they check for destinationFilename differences. We have to change the ending to override the file.
|
||||
destinationFilename: .server.ts
|
||||
client/apis/index.mustache:
|
||||
server/apis/index.mustache:
|
||||
templateType: SupportingFiles
|
||||
destinationFilename: apis/index.ts
|
||||
server/index.mustache:
|
||||
templateType: SupportingFiles
|
||||
destinationFilename: index.ts
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
*/
|
||||
{{/description}}
|
||||
{{^isEnum}}
|
||||
export interface {{classname}} {
|
||||
export {{#isNullable}}type{{/isNullable}}{{^isNullable}}interface{{/isNullable}} {{classname}} {{#isNullable}}={{/isNullable}} {
|
||||
{{>modelGenericAdditionalProperties}}
|
||||
{{#vars}}
|
||||
{{#description}}
|
||||
@@ -19,7 +19,7 @@ export interface {{classname}} {
|
||||
{{/description}}
|
||||
'{{name}}'{{^required}}?{{/required}}: {{#isEnum}}{{{datatypeWithEnum}}}{{/isEnum}}{{^isEnum}}{{{dataType}}}{{/isEnum}}{{#isNullable}} | null{{/isNullable}};
|
||||
{{/vars}}
|
||||
}
|
||||
}{{#isNullable}} | null{{/isNullable}}
|
||||
|
||||
{{#hasEnums}}
|
||||
|
||||
|
||||
@@ -1,15 +1,9 @@
|
||||
{{>licenseInfo}}
|
||||
import type {
|
||||
PathTemplate,RequestMatcherByModelAndPath,RequestMatcherByModelAndPathParams
|
||||
} from '@backstage/backend-openapi-utils';
|
||||
import type {
|
||||
{{#imports}}
|
||||
{{classname}},
|
||||
{{/imports}}
|
||||
} from '{{clientPackageName}}';
|
||||
import {Router} from 'express';
|
||||
|
||||
type ExtendsString<Path extends string> = Path;
|
||||
|
||||
|
||||
{{#operations}}
|
||||
@@ -17,31 +11,29 @@ type ExtendsString<Path extends string> = Path;
|
||||
/**
|
||||
* {{{description}}}{{^description}}no description{{/description}}
|
||||
*/
|
||||
{{! export interface TypedRouter extends Router { }}
|
||||
|
||||
type InputOutput = {
|
||||
{{#operation}}
|
||||
|
||||
'{{path}}': {
|
||||
'{{httpMethod}}': {
|
||||
path: {
|
||||
{{#pathParams}}
|
||||
{{paramName}}{{^required}}?{{/required}}: {{{dataType}}},
|
||||
{{/pathParams}}
|
||||
},
|
||||
query: {
|
||||
{{#queryParams}}
|
||||
{{paramName}}{{^required}}?{{/required}}: {{{dataType}}},
|
||||
{{/queryParams}}
|
||||
},
|
||||
{{#bodyParam}}
|
||||
body: {{{dataType}}},
|
||||
{{/bodyParam}}
|
||||
response: {{{returnType}}}{{^returnType}}void{{/returnType}},
|
||||
}
|
||||
export type EndpointMap = {
|
||||
{{#operation}}
|
||||
|
||||
'#{{#lambda.lowercase}}{{httpMethod}}{{/lambda.lowercase}}|{{path}}': {
|
||||
path: {
|
||||
{{#pathParams}}
|
||||
{{paramName}}{{^required}}?{{/required}}: {{{dataType}}},
|
||||
{{/pathParams}}
|
||||
},
|
||||
|
||||
{{/operation}}
|
||||
}
|
||||
{{! } }}
|
||||
query: {
|
||||
{{#queryParams}}
|
||||
{{paramName}}{{^required}}?{{/required}}: {{{dataType}}},
|
||||
{{/queryParams}}
|
||||
},
|
||||
{{#bodyParam}}
|
||||
body: {{{dataType}}},
|
||||
{{/bodyParam}}
|
||||
{{#returnType}}
|
||||
response: {{{returnType}}},
|
||||
{{/returnType}}
|
||||
},
|
||||
|
||||
{{/operation}}
|
||||
}
|
||||
{{/operations}}
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
//
|
||||
|
||||
export * from './DefaultApi.server';
|
||||
@@ -1,61 +0,0 @@
|
||||
{{#lambda.lowercase}}{{httpMethod}}({{/lambda.lowercase}}
|
||||
|
||||
path: ExtendsString<PathTemplate<`{{path}}`>>,
|
||||
...handlers: Array<RequestMatcherByModelAndPath<
|
||||
{
|
||||
{{#pathParams}}
|
||||
{{paramName}}{{^required}}?{{/required}}: {{{dataType}}},
|
||||
{{/pathParams}}
|
||||
},
|
||||
{
|
||||
{{#queryParams}}
|
||||
{{paramName}}{{^required}}?{{/required}}: {{{dataType}}},
|
||||
{{/queryParams}}
|
||||
},
|
||||
{{#hasBodyParam}}
|
||||
{{#bodyParam}}
|
||||
{{{dataType}}}
|
||||
{{/bodyParam}}
|
||||
{{/hasBodyParam}}
|
||||
{{^hasBodyParam}}
|
||||
{}
|
||||
{{/hasBodyParam}},
|
||||
{{#responses}}
|
||||
{{^-first}}
|
||||
|
|
||||
{{/-first}}
|
||||
/**
|
||||
* {{code}} {{message}}
|
||||
*/
|
||||
{{#dataType}}
|
||||
{{{dataType}}}
|
||||
{{/dataType}}
|
||||
{{/responses}}
|
||||
>>
|
||||
): this;
|
||||
|
||||
{{#lambda.lowercase}}{{httpMethod}}({{/lambda.lowercase}}
|
||||
|
||||
path: ExtendsString<PathTemplate<`{{path}}`>>,
|
||||
...handlers: Array<RequestMatcherByModelAndPathParams<
|
||||
{
|
||||
{{#pathParams}}
|
||||
{{paramName}}{{^required}}?{{/required}}: {{{dataType}}},
|
||||
{{/pathParams}}
|
||||
},
|
||||
{
|
||||
{{#queryParams}}
|
||||
{{paramName}}{{^required}}?{{/required}}: {{{dataType}}},
|
||||
{{/queryParams}}
|
||||
},
|
||||
{{#hasBodyParam}}
|
||||
{{#bodyParam}}
|
||||
{{{dataType}}}
|
||||
{{/bodyParam}}
|
||||
{{/hasBodyParam}}
|
||||
{{^hasBodyParam}}
|
||||
{}
|
||||
{{/hasBodyParam}},
|
||||
{{{returnType}}}{{^returnType}}void{{/returnType}}
|
||||
>>
|
||||
): this;
|
||||
@@ -0,0 +1,3 @@
|
||||
//
|
||||
|
||||
export * from './apis';
|
||||
@@ -1,25 +0,0 @@
|
||||
*.md
|
||||
*.mustache
|
||||
apis/baseapi.ts
|
||||
apis/exception.ts
|
||||
auth/*
|
||||
http/*
|
||||
middleware.ts
|
||||
servers.ts
|
||||
util.ts
|
||||
configuration.ts
|
||||
rxjsStub.ts
|
||||
.gitignore
|
||||
apis/*.ts
|
||||
!apis/*.client.ts
|
||||
!apis/*.server.ts
|
||||
models/*.ts
|
||||
!models/*.model.ts
|
||||
!index.ts
|
||||
!**/index.ts
|
||||
types/ObjectParamAPI.ts
|
||||
types/ObservableAPI.ts
|
||||
types/PromiseAPI.ts
|
||||
git_push.sh
|
||||
package.json
|
||||
tsconfig.json
|
||||
@@ -1,3 +0,0 @@
|
||||
apis/DefaultApi.server.ts
|
||||
apis/index.ts
|
||||
index.ts
|
||||
@@ -1 +0,0 @@
|
||||
6.5.0
|
||||
@@ -1,340 +0,0 @@
|
||||
/*
|
||||
* Copyright 2024 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import type core from 'express-serve-static-core';
|
||||
|
||||
import type {
|
||||
AnalyzeLocationRequest,
|
||||
AnalyzeLocationResponse,
|
||||
CreateLocation201Response,
|
||||
CreateLocationRequest,
|
||||
EntitiesBatchResponse,
|
||||
EntitiesQueryResponse,
|
||||
Entity,
|
||||
EntityAncestryResponse,
|
||||
EntityFacetsResponse,
|
||||
GetEntitiesByRefsRequest,
|
||||
GetLocations200ResponseInner,
|
||||
Location,
|
||||
RefreshEntityRequest,
|
||||
ValidateEntityRequest,
|
||||
} from '@backstage/catalog-client';
|
||||
import { Router } from 'express';
|
||||
|
||||
/**
|
||||
* no description
|
||||
*/
|
||||
|
||||
type InputOutput = {
|
||||
'#POST|/analyze-location': {
|
||||
path: {};
|
||||
query: {};
|
||||
body: AnalyzeLocationRequest;
|
||||
response: AnalyzeLocationResponse;
|
||||
};
|
||||
|
||||
'#POST|/locations': {
|
||||
path: {};
|
||||
query: {
|
||||
dryRun?: string;
|
||||
};
|
||||
body: CreateLocationRequest;
|
||||
response: CreateLocation201Response;
|
||||
};
|
||||
|
||||
'#DELETE|/entities/by-uid/{uid}': {
|
||||
path: {
|
||||
uid: string;
|
||||
};
|
||||
query: {};
|
||||
response: void;
|
||||
};
|
||||
|
||||
'#DELETE|/locations/{id}': {
|
||||
path: {
|
||||
id: string;
|
||||
};
|
||||
query: {};
|
||||
response: void;
|
||||
};
|
||||
|
||||
'#GET|/entities': {
|
||||
path: {};
|
||||
query: {
|
||||
fields?: Array<string>;
|
||||
limit?: number;
|
||||
filter?: Array<string>;
|
||||
offset?: number;
|
||||
after?: string;
|
||||
order?: Array<string>;
|
||||
};
|
||||
response: Array<Entity>;
|
||||
};
|
||||
|
||||
'#GET|/entities/by-query': {
|
||||
path: {};
|
||||
query: {
|
||||
fields?: Array<string>;
|
||||
limit?: number;
|
||||
orderField?: Array<string>;
|
||||
cursor?: string;
|
||||
filter?: Array<string>;
|
||||
fullTextFilterTerm?: string;
|
||||
fullTextFilterFields?: Array<string>;
|
||||
};
|
||||
response: EntitiesQueryResponse;
|
||||
};
|
||||
|
||||
'#POST|/entities/by-refs': {
|
||||
path: {};
|
||||
query: {};
|
||||
body: GetEntitiesByRefsRequest;
|
||||
response: EntitiesBatchResponse;
|
||||
};
|
||||
|
||||
'#GET|/entities/by-name/{kind}/{namespace}/{name}/ancestry': {
|
||||
path: {
|
||||
kind: string;
|
||||
namespace: string;
|
||||
name: string;
|
||||
};
|
||||
query: {};
|
||||
response: EntityAncestryResponse;
|
||||
};
|
||||
|
||||
'#GET|/entities/by-name/{kind}/{namespace}/{name}': {
|
||||
path: {
|
||||
kind: string;
|
||||
namespace: string;
|
||||
name: string;
|
||||
};
|
||||
query: {};
|
||||
response: Entity;
|
||||
};
|
||||
|
||||
'#GET|/entities/by-uid/{uid}': {
|
||||
path: {
|
||||
uid: string;
|
||||
};
|
||||
query: {};
|
||||
response: Entity;
|
||||
};
|
||||
|
||||
'#GET|/entity-facets': {
|
||||
path: {};
|
||||
query: {
|
||||
facet: Array<string>;
|
||||
filter?: Array<string>;
|
||||
};
|
||||
response: EntityFacetsResponse;
|
||||
};
|
||||
|
||||
'#GET|/locations/{id}': {
|
||||
path: {
|
||||
id: string;
|
||||
};
|
||||
query: {};
|
||||
response: Location;
|
||||
};
|
||||
|
||||
'/locations': {
|
||||
get: {
|
||||
path: {};
|
||||
query: {};
|
||||
response: Array<GetLocations200ResponseInner>;
|
||||
};
|
||||
};
|
||||
|
||||
'#POST|/refresh': {
|
||||
path: {};
|
||||
query: {};
|
||||
body: RefreshEntityRequest;
|
||||
response: void;
|
||||
};
|
||||
|
||||
'#POST|/validate-entity': {
|
||||
path: {};
|
||||
query: {};
|
||||
body: ValidateEntityRequest;
|
||||
response: void;
|
||||
};
|
||||
};
|
||||
|
||||
type PathTemplate<Path extends string> =
|
||||
Path extends `${infer Prefix}{${infer PathName}}${infer Suffix}`
|
||||
? `${Prefix}:${PathName}${PathTemplate<Suffix>}`
|
||||
: Path;
|
||||
|
||||
type HttpMethods = Uppercase<'all' | 'put' | 'get' | 'post' | 'delete'>;
|
||||
|
||||
type ValueOf<T> = T[keyof T];
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export type Filter<T, U> = T extends U ? T : never;
|
||||
|
||||
type DocPath<Doc extends InputOutput> = ValueOf<{
|
||||
[Template in keyof Doc]: Template extends `#${string}|${infer Path}`
|
||||
? Path
|
||||
: never;
|
||||
}>;
|
||||
|
||||
type DocPathMethod<
|
||||
Doc extends InputOutput,
|
||||
Path extends DocPath<Doc>,
|
||||
> = ValueOf<{
|
||||
[Template in keyof Doc]: Template extends `#${infer Method}|${Path}`
|
||||
? Method extends string
|
||||
? Method
|
||||
: never
|
||||
: never;
|
||||
}>;
|
||||
|
||||
type PathSchema<
|
||||
Doc extends InputOutput,
|
||||
Path extends DocPath<Doc>,
|
||||
Method extends DocPathMethod<Doc, Path>,
|
||||
> = `#${Method}|${Path}` extends keyof Doc
|
||||
? 'path' extends keyof Doc[`#${Method}|${Path}`]
|
||||
? Doc[`#${Method}|${Path}`]['path']
|
||||
: never
|
||||
: never;
|
||||
type RequestBody<
|
||||
Doc extends InputOutput,
|
||||
Path extends DocPath<Doc>,
|
||||
Method extends DocPathMethod<Doc, Path>,
|
||||
> = `#${Method}|${Path}` extends keyof Doc
|
||||
? 'body' extends keyof Doc[`#${Method}|${Path}`]
|
||||
? Doc[`#${Method}|${Path}`]['body']
|
||||
: any
|
||||
: any;
|
||||
type ResponseBody<
|
||||
Doc extends InputOutput,
|
||||
Path extends DocPath<Doc>,
|
||||
Method extends DocPathMethod<Doc, Path>,
|
||||
> = `#${Method}|${Path}` extends keyof Doc
|
||||
? 'response' extends keyof Doc[`#${Method}|${Path}`]
|
||||
? Doc[`#${Method}|${Path}`]['response']
|
||||
: any
|
||||
: any;
|
||||
type QuerySchema<
|
||||
Doc extends InputOutput,
|
||||
Path extends DocPath<Doc>,
|
||||
Method extends DocPathMethod<Doc, Path>,
|
||||
> = `#${Method}|${Path}` extends keyof Doc
|
||||
? 'query' extends keyof Doc[`#${Method}|${Path}`]
|
||||
? Doc[`#${Method}|${Path}`]['query']
|
||||
: never
|
||||
: never;
|
||||
|
||||
/**
|
||||
* Typed express request handler.
|
||||
* @public
|
||||
*/
|
||||
export type DocRequestHandler<
|
||||
Doc extends InputOutput,
|
||||
Path extends DocPath<Doc>,
|
||||
Method extends DocPathMethod<Doc, Path>,
|
||||
> = core.RequestHandler<
|
||||
PathSchema<Doc, Path, Method>,
|
||||
ResponseBody<Doc, Path, Method>,
|
||||
RequestBody<Doc, Path, Method>,
|
||||
QuerySchema<Doc, Path, Method>,
|
||||
Record<string, string>
|
||||
>;
|
||||
|
||||
/**
|
||||
* Typed express error handler / request handler union type.
|
||||
* @public
|
||||
*/
|
||||
export type DocRequestHandlerParams<
|
||||
Doc extends InputOutput,
|
||||
Path extends DocPath<Doc>,
|
||||
Method extends DocPathMethod<Doc, Path>,
|
||||
> = core.RequestHandlerParams<
|
||||
PathSchema<Doc, Path, Method>,
|
||||
ResponseBody<Doc, Path, Method>,
|
||||
RequestBody<Doc, Path, Method>,
|
||||
QuerySchema<Doc, Path, Method>,
|
||||
Record<string, string>
|
||||
>;
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export type MethodAwareDocPath<
|
||||
Doc extends InputOutput,
|
||||
Path extends DocPath<Doc>,
|
||||
Method extends DocPathMethod<Doc, Path>,
|
||||
> = ValueOf<{
|
||||
[Template in keyof Doc]: Template extends `#${Method}|${Path}` ? Path : never;
|
||||
}>;
|
||||
|
||||
/**
|
||||
* Superset of the express router path matcher that enforces typed request and response bodies.
|
||||
* @public
|
||||
*/
|
||||
export interface DocRequestMatcher<
|
||||
Doc extends InputOutput,
|
||||
T,
|
||||
Method extends HttpMethods,
|
||||
> {
|
||||
<TPath extends MethodAwareDocPath<Doc, DocPath<Doc>, Method>>(
|
||||
path: PathTemplate<TPath>,
|
||||
...handlers: Array<DocRequestHandler<Doc, TPath, Method>>
|
||||
): T;
|
||||
<TPath extends MethodAwareDocPath<Doc, DocPath<Doc>, Method>>(
|
||||
path: PathTemplate<TPath>,
|
||||
...handlers: Array<DocRequestHandlerParams<Doc, TPath, Method>>
|
||||
): T;
|
||||
}
|
||||
|
||||
export interface TypedRouter extends Router {
|
||||
get: DocRequestMatcher<InputOutput, this, 'GET'>;
|
||||
post: DocRequestMatcher<InputOutput, this, 'POST'>;
|
||||
put: DocRequestMatcher<InputOutput, this, 'PUT'>;
|
||||
delete: DocRequestMatcher<InputOutput, this, 'DELETE'>;
|
||||
}
|
||||
|
||||
type method = DocRequestMatcher<InputOutput, Router, 'POST'>;
|
||||
|
||||
type test2 = keyof method;
|
||||
|
||||
type paths = PathTemplate<DocPath<InputOutput>>;
|
||||
type test3 = PathSchema<
|
||||
InputOutput,
|
||||
'/entities/by-name/{kind}/{namespace}/{name}',
|
||||
'GET'
|
||||
>;
|
||||
|
||||
type test4 = ResponseBody<
|
||||
InputOutput,
|
||||
'/entities/by-name/{kind}/{namespace}/{name}',
|
||||
'GET'
|
||||
>;
|
||||
type Method = DocPath<InputOutput>;
|
||||
type why = DocPathMethod<
|
||||
InputOutput,
|
||||
'/entities/by-name/{kind}/{namespace}/{name}'
|
||||
>;
|
||||
|
||||
type test5 = MethodAwareDocPath<InputOutput, '/entities', 'GET'>;
|
||||
|
||||
const router: TypedRouter = Router() as TypedRouter;
|
||||
router.post('/entities', (req, res) => {
|
||||
res.json([{}]);
|
||||
});
|
||||
@@ -17,7 +17,6 @@
|
||||
// ******************************************************************
|
||||
// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. *
|
||||
// ******************************************************************
|
||||
|
||||
import type {
|
||||
AnalyzeLocationRequest,
|
||||
AnalyzeLocationResponse,
|
||||
@@ -39,168 +38,145 @@ import type {
|
||||
* no description
|
||||
*/
|
||||
|
||||
type InputOutput = {
|
||||
'/analyze-location': {
|
||||
POST: {
|
||||
path: {};
|
||||
query: {};
|
||||
body: AnalyzeLocationRequest;
|
||||
response: AnalyzeLocationResponse;
|
||||
};
|
||||
export type EndpointMap = {
|
||||
'#post|/analyze-location': {
|
||||
path: {};
|
||||
query: {};
|
||||
body: AnalyzeLocationRequest;
|
||||
response: AnalyzeLocationResponse;
|
||||
};
|
||||
|
||||
'/locations': {
|
||||
POST: {
|
||||
path: {};
|
||||
query: {
|
||||
dryRun?: string;
|
||||
};
|
||||
body: CreateLocationRequest;
|
||||
response: CreateLocation201Response;
|
||||
};
|
||||
DELETE: {
|
||||
path: {
|
||||
id: string;
|
||||
};
|
||||
query: {};
|
||||
response: void;
|
||||
};
|
||||
GET: {
|
||||
path: {};
|
||||
query: {};
|
||||
response: Array<GetLocations200ResponseInner>;
|
||||
'#post|/locations': {
|
||||
path: {};
|
||||
query: {
|
||||
dryRun?: string;
|
||||
};
|
||||
body: CreateLocationRequest;
|
||||
response: CreateLocation201Response;
|
||||
};
|
||||
|
||||
'/entities/by-uid/{uid}': {
|
||||
DELETE: {
|
||||
path: {
|
||||
uid: string;
|
||||
};
|
||||
query: {};
|
||||
response: void;
|
||||
};
|
||||
GET: {
|
||||
path: {
|
||||
uid: string;
|
||||
};
|
||||
query: {};
|
||||
response: Entity;
|
||||
'#_delete|/entities/by-uid/{uid}': {
|
||||
path: {
|
||||
uid: string;
|
||||
};
|
||||
query: {};
|
||||
response: void;
|
||||
};
|
||||
|
||||
'/entities': {
|
||||
GET: {
|
||||
path: {};
|
||||
query: {
|
||||
fields?: Array<string>;
|
||||
limit?: number;
|
||||
filter?: Array<string>;
|
||||
offset?: number;
|
||||
after?: string;
|
||||
order?: Array<string>;
|
||||
};
|
||||
response: Array<Entity>;
|
||||
'#_delete|/locations/{id}': {
|
||||
path: {
|
||||
id: string;
|
||||
};
|
||||
query: {};
|
||||
response: void;
|
||||
};
|
||||
|
||||
'/entities/by-query': {
|
||||
GET: {
|
||||
path: {};
|
||||
query: {
|
||||
fields?: Array<string>;
|
||||
limit?: number;
|
||||
orderField?: Array<string>;
|
||||
cursor?: string;
|
||||
filter?: Array<string>;
|
||||
fullTextFilterTerm?: string;
|
||||
fullTextFilterFields?: Array<string>;
|
||||
};
|
||||
response: EntitiesQueryResponse;
|
||||
'#get|/entities': {
|
||||
path: {};
|
||||
query: {
|
||||
fields?: Array<string>;
|
||||
limit?: number;
|
||||
filter?: Array<string>;
|
||||
offset?: number;
|
||||
after?: string;
|
||||
order?: Array<string>;
|
||||
};
|
||||
response: Array<Entity>;
|
||||
};
|
||||
|
||||
'/entities/by-refs': {
|
||||
POST: {
|
||||
path: {};
|
||||
query: {};
|
||||
body: GetEntitiesByRefsRequest;
|
||||
response: EntitiesBatchResponse;
|
||||
'#get|/entities/by-query': {
|
||||
path: {};
|
||||
query: {
|
||||
fields?: Array<string>;
|
||||
limit?: number;
|
||||
orderField?: Array<string>;
|
||||
cursor?: string;
|
||||
filter?: Array<string>;
|
||||
fullTextFilterTerm?: string;
|
||||
fullTextFilterFields?: Array<string>;
|
||||
};
|
||||
response: EntitiesQueryResponse;
|
||||
};
|
||||
|
||||
'/entities/by-name/{kind}/{namespace}/{name}/ancestry': {
|
||||
GET: {
|
||||
path: {
|
||||
kind: string;
|
||||
namespace: string;
|
||||
name: string;
|
||||
};
|
||||
query: {};
|
||||
response: EntityAncestryResponse;
|
||||
};
|
||||
'#post|/entities/by-refs': {
|
||||
path: {};
|
||||
query: {};
|
||||
body: GetEntitiesByRefsRequest;
|
||||
response: EntitiesBatchResponse;
|
||||
};
|
||||
|
||||
'/entities/by-name/{kind}/{namespace}/{name}': {
|
||||
GET: {
|
||||
path: {
|
||||
kind: string;
|
||||
namespace: string;
|
||||
name: string;
|
||||
};
|
||||
query: {};
|
||||
response: Entity;
|
||||
'#get|/entities/by-name/{kind}/{namespace}/{name}/ancestry': {
|
||||
path: {
|
||||
kind: string;
|
||||
namespace: string;
|
||||
name: string;
|
||||
};
|
||||
query: {};
|
||||
response: EntityAncestryResponse;
|
||||
};
|
||||
|
||||
'/entity-facets': {
|
||||
GET: {
|
||||
path: {};
|
||||
query: {
|
||||
facet: Array<string>;
|
||||
filter?: Array<string>;
|
||||
};
|
||||
response: EntityFacetsResponse;
|
||||
'#get|/entities/by-name/{kind}/{namespace}/{name}': {
|
||||
path: {
|
||||
kind: string;
|
||||
namespace: string;
|
||||
name: string;
|
||||
};
|
||||
query: {};
|
||||
response: Entity;
|
||||
};
|
||||
|
||||
'/locations/{id}': {
|
||||
GET: {
|
||||
path: {
|
||||
id: string;
|
||||
};
|
||||
query: {};
|
||||
response: Location;
|
||||
'#get|/entities/by-uid/{uid}': {
|
||||
path: {
|
||||
uid: string;
|
||||
};
|
||||
query: {};
|
||||
response: Entity;
|
||||
};
|
||||
|
||||
'/locations/by-entity/{kind}/{namespace}/{name}': {
|
||||
GET: {
|
||||
path: {
|
||||
kind: string;
|
||||
namespace: string;
|
||||
name: string;
|
||||
};
|
||||
query: {};
|
||||
response: Location;
|
||||
'#get|/entity-facets': {
|
||||
path: {};
|
||||
query: {
|
||||
facet: Array<string>;
|
||||
filter?: Array<string>;
|
||||
};
|
||||
response: EntityFacetsResponse;
|
||||
};
|
||||
|
||||
'/refresh': {
|
||||
POST: {
|
||||
path: {};
|
||||
query: {};
|
||||
body: RefreshEntityRequest;
|
||||
response: void;
|
||||
'#get|/locations/{id}': {
|
||||
path: {
|
||||
id: string;
|
||||
};
|
||||
query: {};
|
||||
response: Location;
|
||||
};
|
||||
|
||||
'/validate-entity': {
|
||||
POST: {
|
||||
path: {};
|
||||
query: {};
|
||||
body: ValidateEntityRequest;
|
||||
response: void;
|
||||
'#get|/locations/by-entity/{kind}/{namespace}/{name}': {
|
||||
path: {
|
||||
kind: string;
|
||||
namespace: string;
|
||||
name: string;
|
||||
};
|
||||
query: {};
|
||||
response: Location;
|
||||
};
|
||||
|
||||
'#get|/locations': {
|
||||
path: {};
|
||||
query: {};
|
||||
response: Array<GetLocations200ResponseInner>;
|
||||
};
|
||||
|
||||
'#post|/refresh': {
|
||||
path: {};
|
||||
query: {};
|
||||
body: RefreshEntityRequest;
|
||||
response: void;
|
||||
};
|
||||
|
||||
'#post|/validate-entity': {
|
||||
path: {};
|
||||
query: {};
|
||||
body: ValidateEntityRequest;
|
||||
response: void;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -14,5 +14,4 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
export * from './DefaultApi.client';
|
||||
export * from './DefaultApi.server';
|
||||
|
||||
@@ -1,207 +0,0 @@
|
||||
/*
|
||||
* Copyright 2023 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Pulled from https://github.com/varanauskas/oatx.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Get value types of `T`.
|
||||
* @public
|
||||
*/
|
||||
export type ValueOf<T> = T[keyof T];
|
||||
|
||||
/**
|
||||
* All paths for a given doc,
|
||||
* @example `/pet/{petId}` | `/pet`
|
||||
* @public
|
||||
*/
|
||||
export type DocPath<Doc extends PathDoc> = Extract<keyof Doc['paths'], string>;
|
||||
|
||||
/**
|
||||
* Validate a string against OpenAPI path template, {@link https://spec.openapis.org/oas/v3.1.0#path-templating-matching}.
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* const path: PathTemplate<"/posts/{postId}/comments/{commentId}"> = "/posts/:postId/comments/:commentId";
|
||||
* const pathWithoutParams: PathTemplate<"/posts/comments"> = "/posts/comments";
|
||||
* ```
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type PathTemplate<Path extends string> =
|
||||
Path extends `${infer Prefix}{${infer PathName}}${infer Suffix}`
|
||||
? `${Prefix}:${PathName}${PathTemplate<Suffix>}`
|
||||
: Path;
|
||||
|
||||
/**
|
||||
* Extract path as specified in OpenAPI `Doc` based on request path
|
||||
* @example
|
||||
* ```ts
|
||||
* const spec = {
|
||||
* paths: {
|
||||
* "/posts/{postId}/comments/{commentId}": {},
|
||||
* "/posts/comments": {},
|
||||
* }
|
||||
* };
|
||||
* const specPathWithParams: DocPath<typeof spec, "/posts/:postId/comments/:commentId"> = "/posts/{postId}/comments/{commentId}";
|
||||
* const specPathWithoutParams: DocPath<typeof spec, "/posts/comments"> = "/posts/comments";
|
||||
* ```
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type TemplateToDocPath<
|
||||
Doc extends PathDoc,
|
||||
Path extends DocPathTemplate<Doc>,
|
||||
> = ValueOf<{
|
||||
[Template in DocPath<Doc>]: Path extends PathTemplate<Template>
|
||||
? Template
|
||||
: never;
|
||||
}>;
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export type DocPathTemplate<Doc extends PathDoc> = PathTemplate<DocPath<Doc>>;
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export type DocPathMethod<
|
||||
Doc extends Pick<RequiredDoc, 'paths'>,
|
||||
Path extends DocPath<Doc>,
|
||||
> = keyof Doc['paths'][Path];
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export type DocPathTemplateMethod<
|
||||
Doc extends Pick<RequiredDoc, 'paths'>,
|
||||
Path extends DocPathTemplate<Doc>,
|
||||
> = keyof Doc['paths'][TemplateToDocPath<Doc, Path>];
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export type MethodAwareDocPath<
|
||||
Doc extends PathDoc,
|
||||
Path extends DocPathTemplate<Doc>,
|
||||
Method extends DocPathTemplateMethod<Doc, Path>,
|
||||
> = ValueOf<{
|
||||
[Template in DocPath<Doc>]: Path extends PathTemplate<Template>
|
||||
? Method extends DocPathTemplateMethod<Doc, Path>
|
||||
? PathTemplate<Template>
|
||||
: never
|
||||
: never;
|
||||
}>;
|
||||
|
||||
/**
|
||||
* From {@link https://stackoverflow.com/questions/71393738/typescript-intersection-not-union-type-from-json-schema}
|
||||
*
|
||||
* StackOverflow says not to do this, but union types aren't possible any other way.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type UnionToIntersection<U> = (
|
||||
U extends any ? (k: U) => void : never
|
||||
) extends (k: infer I) => void
|
||||
? I
|
||||
: never;
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export type LastOf<T> = UnionToIntersection<
|
||||
T extends any ? () => T : never
|
||||
> extends () => infer R
|
||||
? R
|
||||
: never;
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export type Push<T extends any[], V> = [...T, V];
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export type TuplifyUnion<
|
||||
T,
|
||||
L = LastOf<T>,
|
||||
N = [T] extends [never] ? true : false,
|
||||
> = true extends N ? [] : Push<TuplifyUnion<Exclude<T, L>>, L>;
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export type UnknownIfNever<P> = [P] extends [never] ? unknown : P;
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export type DiscriminateUnion<T, K extends keyof T, V extends T[K]> = Extract<
|
||||
T,
|
||||
Record<K, V>
|
||||
>;
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export type MapDiscriminatedUnion<
|
||||
T extends Record<K, string>,
|
||||
K extends keyof T,
|
||||
> = {
|
||||
[V in T[K]]: DiscriminateUnion<T, K, V>;
|
||||
};
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export type PickOptionalKeys<T extends { [key: string]: any }> = {
|
||||
[K in keyof T]: true extends T[K]['required'] ? never : K;
|
||||
}[keyof T];
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export type PickRequiredKeys<T extends { [key: string]: any }> = {
|
||||
[K in keyof T]: true extends T[K]['required'] ? K : never;
|
||||
}[keyof T];
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export type OptionalMap<T extends { [key: string]: any }> = {
|
||||
[P in Exclude<PickOptionalKeys<T>, undefined>]?: NonNullable<T[P]>;
|
||||
};
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export type RequiredMap<T extends { [key: string]: any }> = {
|
||||
[P in Exclude<PickRequiredKeys<T>, undefined>]: NonNullable<T[P]>;
|
||||
};
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export type FullMap<T extends { [key: string]: any }> = RequiredMap<T> &
|
||||
OptionalMap<T>;
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export type Filter<T, U> = T extends U ? T : never;
|
||||
@@ -13,15 +13,5 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
export * from "./http/http";
|
||||
export * from "./auth/auth";
|
||||
export * from "./models/all";
|
||||
export { createConfiguration } from "./configuration"
|
||||
export { Configuration } from "./configuration"
|
||||
export * from "./apis/exception";
|
||||
export * from "./servers";
|
||||
export { RequiredError } from "./apis/baseapi";
|
||||
|
||||
export { PromiseMiddleware as Middleware } from './middleware';
|
||||
export { PromiseDefaultApi as DefaultApi } from './types/PromiseAPI';
|
||||
|
||||
export * from './apis';
|
||||
|
||||
@@ -17,8 +17,8 @@
|
||||
// ******************************************************************
|
||||
// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. *
|
||||
// ******************************************************************
|
||||
import { createValidatedOpenApiRouter } from '@backstage/backend-openapi-utils';
|
||||
import { TypedRouter } from '../generated/apis';
|
||||
import { createValidatedOpenApiRouterFromGeneratedEndpointMap } from '@backstage/backend-openapi-utils';
|
||||
import { EndpointMap } from '../generated';
|
||||
|
||||
export const spec = {
|
||||
openapi: '3.0.3',
|
||||
@@ -1603,5 +1603,11 @@ export const spec = {
|
||||
},
|
||||
} as const;
|
||||
export const createOpenApiRouter = async (
|
||||
options?: Parameters<typeof createValidatedOpenApiRouter>['1'],
|
||||
) => createValidatedOpenApiRouter<typeof spec>(spec, options);
|
||||
options?: Parameters<
|
||||
typeof createValidatedOpenApiRouterFromGeneratedEndpointMap
|
||||
>['1'],
|
||||
) =>
|
||||
createValidatedOpenApiRouterFromGeneratedEndpointMap<EndpointMap>(
|
||||
spec,
|
||||
options,
|
||||
);
|
||||
|
||||
@@ -57,7 +57,6 @@ import {
|
||||
} from '@backstage/backend-plugin-api';
|
||||
import { LocationAnalyzer } from '@backstage/plugin-catalog-node';
|
||||
import { AuthorizedValidationService } from './AuthorizedValidationService';
|
||||
import { TypedRouter } from '../generated/apis';
|
||||
|
||||
/**
|
||||
* Options used by {@link createRouter}.
|
||||
@@ -86,13 +85,13 @@ export interface RouterOptions {
|
||||
export async function createRouter(
|
||||
options: RouterOptions,
|
||||
): Promise<express.Router> {
|
||||
const router = (await createOpenApiRouter({
|
||||
const router = await createOpenApiRouter({
|
||||
validatorOptions: {
|
||||
// We want the spec to be up to date with the expected value, but the return type needs
|
||||
// to be controlled by the router implementation not the request validator.
|
||||
ignorePaths: /^\/validate-entity\/?$/,
|
||||
},
|
||||
})) as TypedRouter;
|
||||
});
|
||||
const {
|
||||
entitiesCatalog,
|
||||
locationAnalyzer,
|
||||
|
||||
Reference in New Issue
Block a user