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
}
}
The controller above emits schema definitions for both NewUserRequest and NewUser. While NewUserRequest is not referenced anywhere else in the schema.
Only NewUser is present in OpenAPI schema.
@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
@requestBodyA 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.
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.