Swagger: ApiModelProperty decorator on a ManyToOne relationship looses type on one side

Created on 9 Mar 2018  Â·  9Comments  Â·  Source: nestjs/swagger

I'm submitting a...


[ ] Regression 
[x] Bug report
[ ] Feature request
[ ] Documentation issue or request
[ ] Support request => Please do not submit support request here, instead post your question on Stack Overflow.

Current behavior

When defining a @ManyToOne with @ApiModelProperty the relation type gets lost in swagger definition and is set as type: ''

UserEntity:
      ...
      app:
        type: ''
      ...

Expected behavior

Swagger definition contains right type on both ends of relation

UserEntity:
      ...
      app:
        type: object
        $ref: '#/definitions/AppEntity'
      ...

Minimal reproduction of the problem with instructions

@Entity()
export class AppEntity {
  @ApiModelPropertyOptional({ type: String })
  @PrimaryGeneratedColumn('uuid')
  id: string

  @ApiModelProperty()
  @Column({ length: 256, nullable: true, default: null })
  name: string

  @ApiModelProperty({ type: UserEntity, isArray: true })
  @OneToMany(type => UserEntity, user => user.app)
  users: UserEntity[]
}
@Entity()
export class UserEntity {
  @ApiModelPropertyOptional({ type: String })
  @PrimaryGeneratedColumn('uuid')
  id: string

  @ApiModelProperty()
  @Column()
  name: string

  @ApiModelProperty({ type: AppEntity })
  @ManyToOne(type => AppEntity, app => app.users)
  app: AppEntity
}

ends up with swagger definition

  UserEntity:
    type: object
    properties:
      id:
        type: string
      name:
        type: string
      app:
        type: ''
    required:
      - name
      - app
  AppEntity:
    type: object
    properties:
      id:
        type: string
      name:
        type: string
      users:
        type: array
        items:
          $ref: '#/definitions/UserEntity'
    required:
      - name
      - users

What is the motivation / use case for changing the behavior?


@ManyToOne / @OneToMany should create correct definition

Environment


    "@nestjs/common": "^4.6.5",
    "@nestjs/core": "^4.6.5",
    "@nestjs/microservices": "^4.6.5",
    "@nestjs/swagger": "^1.1.4",
    "@nestjs/testing": "^4.6.1",
    "@nestjs/typeorm": "^2.0.0",
    "@nestjs/websockets": "^4.6.5",
    "typeorm": "^0.1.16",
    "typescript": "^2.7.2" 
bug next

Most helpful comment

This happens because when you have two models that depend on each other, e.g. AccesToken -> User, User -> AccesToken, one of imports will be undefined when the file first runs. In order the resolve this you need to use a function in the same way the @OneToMany / @ManyToOne decorator does it.

This illustrates the problem:

// user.entity.ts
// Reference to AccessToken class will be 'undefined' at runtime 
// because User and AccessToken depend on each other
@import { AccessToken } from "./acces-token.enitity';
class User {
    ...

    @ApiModelProperty({ 
        // AccessToken is undefined, therefore this type resolves to an empty object
        type: AccessToken ,  
        isArray: true 
     })
    @OneToMany(type => AccessToken, accessTokens => accessTokens.user)
    accessTokens:AccessToken[]
}

---
// access-token.entity.ts

@import { User } from "./user.entity";

class AccessToken {
    ...
    @ApiModelProperty({
        // The User import can be resolved,
        // so this will actually resolve to the User enity type
        type: User, 
     }) 
     @ManyToOne(type => User, user => user.accesTokens)
     user:User
}

A proposed fix is to wrap the related Model in a callback, the same way that @OneToMany does this. E.g.:

  ...
 @ApiModelProperty({ 
        // Using a function that returns a reference to the class fixes the issue, 
        // since the AccesToken class will be resolved when the decorator runs
        type: type => AccessToken ,  
        isArray: true 
     })
    @OneToMany(type => AccessToken, accessTokens => accessTokens.user)
    accessTokens:AccessToken[]

I already requested a merge on this pull request: https://github.com/nestjs/swagger/pull/179 (https://github.com/labibramadhan/swagger/pull/1)

All 9 comments

+1

+1

On Thu, Apr 12, 2018 at 5:46 PM, pokkia notifications@github.com wrote:
+1

—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub [https://github.com/nestjs/swagger/issues/63#issuecomment-380743769] , or mute the thread [https://github.com/notifications/unsubscribe-auth/AALr5Ns9vOussq0ifIxH-FchEU1JOrfTks5tnyJqgaJpZM4SkyWv] .

this is still present in 5.0.2, also this also affects @OneToOne type relations as well. Manually specifying a type such as @ApiModelProperty({type: MyType}) has no affect.

I hope this issue can be improved.

+1

This happens because when you have two models that depend on each other, e.g. AccesToken -> User, User -> AccesToken, one of imports will be undefined when the file first runs. In order the resolve this you need to use a function in the same way the @OneToMany / @ManyToOne decorator does it.

This illustrates the problem:

// user.entity.ts
// Reference to AccessToken class will be 'undefined' at runtime 
// because User and AccessToken depend on each other
@import { AccessToken } from "./acces-token.enitity';
class User {
    ...

    @ApiModelProperty({ 
        // AccessToken is undefined, therefore this type resolves to an empty object
        type: AccessToken ,  
        isArray: true 
     })
    @OneToMany(type => AccessToken, accessTokens => accessTokens.user)
    accessTokens:AccessToken[]
}

---
// access-token.entity.ts

@import { User } from "./user.entity";

class AccessToken {
    ...
    @ApiModelProperty({
        // The User import can be resolved,
        // so this will actually resolve to the User enity type
        type: User, 
     }) 
     @ManyToOne(type => User, user => user.accesTokens)
     user:User
}

A proposed fix is to wrap the related Model in a callback, the same way that @OneToMany does this. E.g.:

  ...
 @ApiModelProperty({ 
        // Using a function that returns a reference to the class fixes the issue, 
        // since the AccesToken class will be resolved when the decorator runs
        type: type => AccessToken ,  
        isArray: true 
     })
    @OneToMany(type => AccessToken, accessTokens => accessTokens.user)
    accessTokens:AccessToken[]

I already requested a merge on this pull request: https://github.com/nestjs/swagger/pull/179 (https://github.com/labibramadhan/swagger/pull/1)

Fixed in the next version (to install run npm i @nestjs/swagger@next). Note: remember to update @nestjs/common, @nestjs/core and typescript as well to ensure that you're using the latest versions.

Steps to migrate: https://github.com/nestjs/swagger/pull/355#issuecomment-547925879

4.0.0 has been published

This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

ericzon picture ericzon  Â·  4Comments

ph55 picture ph55  Â·  3Comments

alisherks picture alisherks  Â·  4Comments

ivashog picture ivashog  Â·  3Comments

mogusbi picture mogusbi  Â·  3Comments