Loopback-next: Overriding title in `getModelSchemaRef` causes duplication in OpenAPI schema

Created on 3 Jun 2020  路  5Comments  路  Source: strongloop/loopback-next

Steps to reproduce


Define a controller with getModelSchemaRef(SomeModel, {title: 'TitleOverride'}).



Controller definition

export class UserController {
  @post('/users', {
    security: OPERATION_SECURITY_SPEC,
    responses: {
      '200': {
        description: 'User',
        content: {
          'application/json': {
            schema: {
              'x-ts-type': User,
            },
          },
        },
      },
    },
  })
  async create(
    @requestBody({
      content: {
        'application/json': {
          schema: getModelSchemaRef(NewUserRequest, {
            title: 'NewUser',
          }),
        },
      },
    })
    newUserRequest: NewUserRequest,
  ): Promise<User> {
    // implementation
  }
}

Current Behavior

The controller above emits schema definitions for both NewUserRequest and NewUser. While NewUserRequest is not referenced anywhere else in the schema.

Expected Behavior


Only NewUser is present in OpenAPI schema.

Additional information

@loopback/[email protected]
@loopback/[email protected]

I presume NewUserRequest is generated from getModelSchemaRef as it should while NewUser comes from parsing paramTypes where it causes a cache miss due to overridden title.

A probable fix could exclude a parameter corresponding to requestBody from enumeration here

https://github.com/strongloop/loopback-next/blob/7f8d8356946dc236dd4daecbfae12e0a0662cf1c/packages/openapi-v3/src/controller-spec.ts#L329

Acceptance Criteria

  • [ ] Don't generate unused schema for parameter decorated with @requestBody

A solution I can think of is:
https://github.com/strongloop/loopback-next/blob/7f8d8356946dc236dd4daecbfae12e0a0662cf1c/packages/openapi-v3/src/controller-spec.ts#L329

should search through the content objects in the request body spec, if all contents' schemas exist in reference, then skip generating the one inferred from model ctor.

bug help wanted

All 5 comments

Hi @InvictusMB I assume you are trying example like todo-jwt. A quick confirm:

This is the OpenAPI spec I get from that app:


Controller definition


"NewUser": {
        "title": "NewUser",
        "description": "(tsType: NewUserRequest, schemaOptions: { title: 'NewUser' })",
        "properties": {
          "id": {
            "type": "string"
          },
          "realm": {
            "type": "string"
          },
          "username": {
            "type": "string"
          },
          "email": {
            "type": "string"
          },
          "emailVerified": {
            "type": "boolean"
          },
          "verificationToken": {
            "type": "string"
          },
          "password": {
            "type": "string"
          }
        },
        "required": [
          "email",
          "password"
        ],
        "additionalProperties": true,
        "x-typescript-type": "NewUserRequest"
      },
      "NewUserRequest": {
        "title": "NewUserRequest",
        "properties": {
          "id": {
            "type": "string"
          },
          "realm": {
            "type": "string"
          },
          "username": {
            "type": "string"
          },
          "email": {
            "type": "string"
          },
          "emailVerified": {
            "type": "boolean"
          },
          "verificationToken": {
            "type": "string"
          },
          "password": {
            "type": "string"
          }
        },
        "required": [
          "email",
          "password"
        ],
        "additionalProperties": true
      },

Do you mean the NewUserRequest schema shouldn't exist? And ONLY NewUser is expected.

Hi @jannyHou
Yes, NewUserRequest should not exist if it is not referenced anywhere else as in my case.

The fix should be something like

for (const p of paramTypes) {
  if (isComplexType(p) && !isRequestBody(p)) {
    generateOpenAPISchema(spec, p);
  }
}

@InvictusMB I double checked the @requestBody decorator, feel it's hard to tell should the schema generation be skipped or not, because in some situation(e.g. if no spec found in the decorator), it must infer the schema from model ctor. For example

see the doc of @requestBody

// no schema provided inside decorator, 
// therefore #L329 has to generate the schema from `User`
@requestBody() user: User

While your report is correct, it shouldn't always generate that unused schema.

A solution I can think of is:
https://github.com/strongloop/loopback-next/blob/7f8d8356946dc236dd4daecbfae12e0a0662cf1c/packages/openapi-v3/src/controller-spec.ts#L329

should search through the content objects in the request body spec, if all contents' schemas exist in reference, then skip generating the one inferred from model ctor.

@InvictusMB, would you be interested to contribute a PR? Thanks.

@dhmlau Not anytime soon. I have a bunch of fat PRs to finalize first.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

half-blood-programmer picture half-blood-programmer  路  3Comments

milindsingh picture milindsingh  路  3Comments

teambitcodeGIT picture teambitcodeGIT  路  3Comments

ThePinger picture ThePinger  路  3Comments

cloudwheels picture cloudwheels  路  3Comments