I would like to enable Swagger for API interfaces, shared between NestJS and Angular app within an Nx monorepo. Is there a consistent and not workaround-looking way?
These are the approaches I haven't succeeded with:
@nestjs/swagger
decorators to the shared DTO classesnpx create-nx-workspace@latest
angular-nest
workspace blueprintMessage
in app.component.ts
(doesn't make sense, just for testing):export class AppComponent {
@Input() message: Message;
hello$ = this.http.get<Message>('/api/hello');
constructor(private http: HttpClient) {}
}
message
property with ApiProperty()
in api-interfaces.ts
:import { ApiProperty } from '@nestjs/swagger';
export class Message {
@ApiProperty()
message: string;
}
WARNING in ./node_modules/@nestjs/common/utils/load-package.util.js 8:39-59
Critical dependency: the request of a dependency is an expression
WARNING in ./node_modules/express/lib/view.js 81:13-25
Critical dependency: the request of a dependency is an expression
WARNING in ./node_modules/@nestjs/mapped-types/dist/type-helpers.utils.js
Module not found: Error: Can't resolve 'class-transformer' in '.\node_modules\@nestjs\mapped-types\dist'
ERROR in ./node_modules/@nestjs/common/cache/cache.providers.js
Module not found: Error: Can't resolve 'cache-manager' in '.\node_modules\@nestjs\common\cache'
ERROR in ./node_modules/@nestjs/common/pipes/validation.pipe.js
Module not found: Error: Can't resolve 'class-transformer' in '.\node_modules\@nestjs\common\pipes'
...
Which looks like a bundling issue, similar to this one. I haven't found any elegant working solution to fix it in Angular build.
This would be even a better way than the previous one, but it didn't work though. First, the Swagger plugin requires NestJS CLI, which is not the case in Nx monorepo. There's an issue suggesting some workarounds, but I haven't found them to be reliable enough and complete. Second, the plugin doesn't cover some important use cases, which still require decorators anyway. For instance:
@ApiProperty({
oneOf: [{ $ref: getSchemaPath(TypeA) }, { $ref: getSchemaPath(TypeB) }],
})
type: TypeA | TypeB;
And as described above, the decorators lead to errors.
What attracts me in this approach is the ability to abstract from the back-end specific logic, either Swagger, serialization, or validation decorators. We could do the following:
// Expose to the back-end
export class MessageDto {
@ApiProperty()
message: string;
}
// Expose to the front-end
export interface Message extends MessageDto {}
In this case, the Message
interface gets compiled well with the Angular app. But as soon as we introduce more complicated DTO compositions (classes with nested DTOs), this approach doesn't work.
I would appreciate any other ideas.
I have succeeded of sharing DTO(s) between Angular and Nest.js (Approach #1)
Replacing @angular-devkit/build-angular:browser
to @angular-builders/custom-webpack:browser
has resolved the errors when building or serving the angular app.
See https://github.com/nestjs/nest/issues/1706#issuecomment-474657479 for more details.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With