initial work

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:
Aramis
2024-01-21 10:35:02 -05:00
committed by aramissennyeydd
parent 16b8fb9dc6
commit ddf9e55c3a
28 changed files with 668 additions and 18 deletions
@@ -31,5 +31,10 @@ export type {
PathParameters,
} from './utility';
export type { ApiRouter } from './router';
export type {
RequestMatcherByModelAndPath,
RequestMatcherByModelAndPathParams,
} from './types/express';
export type { PathTemplate } from './types/common';
export { createValidatedOpenApiRouter, getOpenApiSpecRoute } from './stub';
export { wrapInOpenApiTestServer, wrapServer } from './testUtils';
@@ -100,3 +100,29 @@ export interface DocRequestMatcher<
>
): T;
}
export type RequestMatcherByModelAndPath<
PathParams,
QueryParams,
RequestBody,
ResponseBody,
> = core.RequestHandler<
PathParams,
ResponseBody,
RequestBody,
QueryParams,
Record<string, string>
>;
export type RequestMatcherByModelAndPathParams<
PathParams,
QueryParams,
RequestBody,
ResponseBody,
> = core.RequestHandlerParams<
PathParams,
ResponseBody,
RequestBody,
QueryParams,
Record<string, string>
>;
+3 -1
View File
@@ -21,4 +21,6 @@
*/
export { CatalogClient } from './CatalogClient';
export * from './types';
// export * from './types';
export * from './generated/models';
@@ -0,0 +1,23 @@
*.md
apis/baseapi.ts
apis/exception.ts
auth/*
http/*
middleware.ts
servers.ts
util.ts
configuration.ts
rxjsStub.ts
.gitignore
apis/*.ts
!apis/*.client.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
@@ -0,0 +1,101 @@
/*
* 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);
}
}
@@ -63,7 +63,7 @@ async function generate(
'-c',
resolvePackagePath(
'@backstage/repo-tools',
'templates/typescript-backstage.yaml',
'templates/typescript-backstage.client.yaml',
),
'--generator-key',
'v3.0',
@@ -1,35 +1,35 @@
templateDir: templates/typescript-backstage
files:
api.mustache:
client/api.mustache:
templateType: API
# For some reason, they check for destinationFilename differences. We have to change the ending to override the file.
destinationFilename: .client.ts
model.mustache:
client/model.mustache:
templateType: Model
destinationFilename: .model.ts
modelGeneric.mustache:
client/models/modelGeneric.mustache:
templateType: SupportingFiles
modelOneOf.mustache:
client/models/modelOneOf.mustache:
templateType: SupportingFiles
modelGenericAdditionalProperties.mustache:
client/models/modelGenericAdditionalProperties.mustache:
templateType: SupportingFiles
modelGenericEnums.mustache:
client/models/ modelGenericEnums.mustache:
templateType: SupportingFiles
modelAlias.mustache:
client/models/modelAlias.mustache:
templateType: SupportingFiles
modelEnum.mustache:
client/models/modelEnum.mustache:
templateType: SupportingFiles
modelTaggedUnion.mustache:
client/models/modelTaggedUnion.mustache:
templateType: SupportingFiles
models/models_all.mustache:
client/models/models_all.mustache:
templateType: SupportingFiles
destinationFilename: models/index.ts
types/fetch.ts: {}
types/discovery.ts: {}
apis/index.mustache:
client/types/fetch.ts: {}
client/types/discovery.ts: {}
client/apis/index.mustache:
templateType: SupportingFiles
destinationFilename: apis/index.ts
pluginId.mustache:
client/pluginId.mustache:
templateType: SupportingFiles
destinationFilename: pluginId.ts
@@ -0,0 +1,10 @@
templateDir: templates/typescript-backstage
files:
server/api.mustache:
templateType: API
# For some reason, they check for destinationFilename differences. We have to change the ending to override the file.
destinationFilename: .client.ts
client/apis/index.mustache:
templateType: SupportingFiles
destinationFilename: apis/index.ts
@@ -0,0 +1,45 @@
{{>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}}
/**
* {{{description}}}{{^description}}no description{{/description}}
*/
{{! export interface TypedRouter extends Router { }}
type InputOutput = {
{{#operation}}
'#{{httpMethod}}|{{path}}': {
path: {
{{#pathParams}}
{{paramName}}{{^required}}?{{/required}}: {{{dataType}}},
{{/pathParams}}
},
query: {
{{#queryParams}}
{{paramName}}{{^required}}?{{/required}}: {{{dataType}}},
{{/queryParams}}
},
{{#bodyParam}}
body: {{{dataType}}},
{{/bodyParam}}
response: {{{returnType}}}{{^returnType}}void{{/returnType}},
},
{{/operation}}
}
{{! } }}
{{/operations}}
@@ -0,0 +1,61 @@
{{#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;