Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to enable Swagger for API interfaces shared between NestJS and Angular within Nx monorepo?

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:

Approach 1. Apply @nestjs/swagger decorators to the shared DTO classes

  • create a new Nx monorepo with npx create-nx-workspace@latest
  • select the angular-nest workspace blueprint
  • install Swagger dependencies and bootstrap it according to the guide
  • add input of type Message 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) {}
}
  • decorate message property with ApiProperty() in api-interfaces.ts:
import { ApiProperty } from '@nestjs/swagger';

export class Message {
  @ApiProperty()
  message: string;
}
  • run the NestJS app. It works fine, Swagger displays correct DTO structure in the Web view
  • however, when I start the Angular app, I get errors:
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.

Approach 2. Use NestJS Swagger plugin and avoid decorators

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.

Approach 3. Create interfaces out of DTO classes for dedicated use in the Angular app

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.

like image 859
Andriy Chuma Avatar asked May 11 '20 00:05

Andriy Chuma


1 Answers

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.

like image 143
ngson2000 Avatar answered Oct 09 '22 22:10

ngson2000