Reputation: 9976
I am writing a NestJS application. Now I want to install the Express middleware express-openapi-validator.
However, I can't get it to work. There is a description for how to install the express-openapi-validator in express, but it always results in errors.
For example
export class AppModule implements NestModule {
configure(consumer: MiddlewareConsumer) {
consumer.apply(middleware({apiSpec "./bff-api.yaml"}))
.forRoutes(OrganizationController)
}
}
results in
error TS2345: Argument of type 'OpenApiRequestHandler[]' is not assignable to parameter of type 'Function | Type<any>'.
Type 'OpenApiRequestHandler[]' is missing the following properties from type 'Type<any>': apply, call, bind, prototype, and 4 more.
How can I install this middleware in NestJS?
Upvotes: 3
Views: 1643
Reputation: 1139
I added a NestJS example to express-openapi-validator (static link for posterity).
The AppModule
looks basically identical, although you don't need to iterate over the middlewares:
@Module({
imports: [PingModule],
providers: [{ provide: APP_FILTER, useClass: OpenApiExceptionFilter }],
})
export class AppModule implements NestModule {
configure(consumer: MiddlewareConsumer) {
consumer
.apply(
...OpenApiValidator.middleware({
apiSpec: join(__dirname, './api.yaml'),
}),
)
.forRoutes('*');
}
}
I also added an exception filter to convert the error from express-openapi-validator
to a proper response; otherwise I would always get a 500 error. You could also use this approach to convert the error into a custom error format.
import { ArgumentsHost, Catch, ExceptionFilter } from '@nestjs/common';
import { Response } from 'express';
import { error } from 'express-openapi-validator';
@Catch(...Object.values(error))
export class OpenApiExceptionFilter implements ExceptionFilter {
catch(error: ValidationError, host: ArgumentsHost) {
const ctx = host.switchToHttp();
const response = ctx.getResponse<Response>();
response.status(error.status).json(error);
}
}
interface ValidationError {
status: number;
message: string;
errors: Array<{
path: string;
message: string;
error_code?: string;
}>;
path?: string;
name: string;
}
Upvotes: 4
Reputation: 9976
I have now got it working:
configure(consumer: MiddlewareConsumer) {
middleware({
apiSpec: `${__dirname}/../api-doc/bff-api.yaml`
}).forEach(value => consumer.apply(value).forRoutes(OrganizationController))
}
Upvotes: 1