2022-05-04 15:16:18 +02:00
|
|
|
import openapi, { IExpressOpenApi } from '@unleash/express-openapi';
|
2022-06-08 08:01:14 +02:00
|
|
|
import { Express, RequestHandler, Response } from 'express';
|
2022-04-25 14:17:59 +02:00
|
|
|
import { IUnleashConfig } from '../types/option';
|
2022-06-08 08:01:14 +02:00
|
|
|
import {
|
|
|
|
createOpenApiSchema,
|
2022-06-10 10:04:56 +02:00
|
|
|
JsonSchemaProps,
|
|
|
|
removeJsonSchemaProps,
|
2022-06-08 08:01:14 +02:00
|
|
|
SchemaId,
|
|
|
|
} from '../openapi';
|
2022-07-01 08:06:33 +02:00
|
|
|
import { ApiOperation } from '../openapi/util/api-operation';
|
2022-06-08 08:01:14 +02:00
|
|
|
import { Logger } from '../logger';
|
|
|
|
import { validateSchema } from '../openapi/validate';
|
2022-04-25 14:17:59 +02:00
|
|
|
|
|
|
|
export class OpenApiService {
|
|
|
|
private readonly config: IUnleashConfig;
|
|
|
|
|
2022-06-08 08:01:14 +02:00
|
|
|
private readonly logger: Logger;
|
|
|
|
|
2022-05-04 15:16:18 +02:00
|
|
|
private readonly api: IExpressOpenApi;
|
2022-04-25 14:17:59 +02:00
|
|
|
|
|
|
|
constructor(config: IUnleashConfig) {
|
|
|
|
this.config = config;
|
2022-06-08 08:01:14 +02:00
|
|
|
this.logger = config.getLogger('openapi-service.ts');
|
|
|
|
|
2022-04-25 14:17:59 +02:00
|
|
|
this.api = openapi(
|
|
|
|
this.docsPath(),
|
2022-06-27 15:39:08 +02:00
|
|
|
createOpenApiSchema(config.server),
|
2022-05-04 15:16:18 +02:00
|
|
|
{ coerce: true },
|
2022-04-25 14:17:59 +02:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2022-06-23 09:40:25 +02:00
|
|
|
validPath(op: ApiOperation): RequestHandler {
|
2022-04-25 14:17:59 +02:00
|
|
|
return this.api.validPath(op);
|
|
|
|
}
|
|
|
|
|
|
|
|
useDocs(app: Express): void {
|
|
|
|
app.use(this.api);
|
|
|
|
app.use(this.docsPath(), this.api.swaggerui);
|
|
|
|
}
|
|
|
|
|
|
|
|
docsPath(): string {
|
|
|
|
const { baseUriPath = '' } = this.config.server ?? {};
|
|
|
|
return `${baseUriPath}/docs/openapi`;
|
|
|
|
}
|
|
|
|
|
2022-06-10 10:04:56 +02:00
|
|
|
registerCustomSchemas<T extends JsonSchemaProps>(
|
|
|
|
schemas: Record<string, T>,
|
|
|
|
): void {
|
2022-04-25 14:17:59 +02:00
|
|
|
Object.entries(schemas).forEach(([name, schema]) => {
|
2022-06-10 10:04:56 +02:00
|
|
|
this.api.schema(name, removeJsonSchemaProps(schema));
|
2022-04-25 14:17:59 +02:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
useErrorHandler(app: Express): void {
|
|
|
|
app.use((err, req, res, next) => {
|
|
|
|
if (err && err.status && err.validationErrors) {
|
|
|
|
res.status(err.status).json({
|
|
|
|
error: err.message,
|
|
|
|
validation: err.validationErrors,
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
next();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
2022-06-08 08:01:14 +02:00
|
|
|
|
|
|
|
respondWithValidation<T>(
|
|
|
|
status: number,
|
|
|
|
res: Response<T>,
|
|
|
|
schema: SchemaId,
|
|
|
|
data: T,
|
|
|
|
): void {
|
|
|
|
const errors = validateSchema(schema, data);
|
|
|
|
|
|
|
|
if (errors) {
|
2022-08-08 10:27:53 +02:00
|
|
|
this.logger.debug('Invalid response:', errors);
|
2022-06-08 08:01:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
res.status(status).json(data);
|
|
|
|
}
|
2022-04-25 14:17:59 +02:00
|
|
|
}
|