-
-
Notifications
You must be signed in to change notification settings - Fork 7.4k
Description
Bug Report Checklist
- Have you provided a full/minimal spec to reproduce the issue?
- Have you validated the input using an OpenAPI validator (example)?
- Have you tested with the latest master to confirm the issue still exists?
- Have you searched for related issues/PRs?
- What's the actual output vs expected output?
- [Optional] Sponsorship to speed up the bug fix or feature request (example)
Description
OpenAPI Generator's generated Python-FastAPI code works by your implementation subclassing a base API module, and then the generated router module (ie: apis/pet_api.py) calls one of the subclasses of a base API module (ie: apis/pet_api_base.py).
The generated router method a reference to a TokenModel (token_petstore_auth), but this is attribute is never passed to the subclass add_pet() implementation:
openapi-generator/samples/server/petstore/python-fastapi/src/openapi_server/apis/pet_api.py
Lines 50 to 59 in 98cd9bd
| async def add_pet( | |
| pet: Annotated[Pet, Field(description="Pet object that needs to be added to the store")] = Body(None, description="Pet object that needs to be added to the store"), | |
| token_petstore_auth: TokenModel = Security( | |
| get_token_petstore_auth, scopes=["write:pets", "read:pets"] | |
| ), | |
| ) -> Pet: | |
| """""" | |
| if not BasePetApi.subclasses: | |
| raise HTTPException(status_code=500, detail="Not implemented") | |
| return await BasePetApi.subclasses[0]().add_pet(pet) |
That code is generated here, where there is no reference to {{#authMethods}} in the method body, only {{#allParams}}:
openapi-generator/modules/openapi-generator/src/main/resources/python-fastapi/api.mustache
Lines 62 to 71 in 98cd9bd
| token_{{name}}: TokenModel = Security( | |
| get_token_{{name}}{{#isOAuth}}, scopes=[{{#scopes}}"{{scope}}"{{^-last}}, {{/-last}}{{/scopes}}]{{/isOAuth}} | |
| ), | |
| {{/authMethods}} | |
| {{/hasAuthMethods}} | |
| ) -> {{returnType}}{{^returnType}}None{{/returnType}}: | |
| {{#notes}}"""{{.}}""" | |
| {{/notes}}if not Base{{classname}}.subclasses: | |
| raise HTTPException(status_code=500, detail="Not implemented") | |
| return await Base{{classname}}.subclasses[0]().{{operationId}}({{#allParams}}{{>impl_argument}}{{^-last}}, {{/-last}}{{/allParams}}) |
And the TokenModel doesn't appear in the base API module (ie: apis/pet_api_base.py):
openapi-generator/samples/server/petstore/python-fastapi/src/openapi_server/apis/pet_api_base.py
Lines 15 to 23 in 98cd9bd
| def __init_subclass__(cls, **kwargs): | |
| super().__init_subclass__(**kwargs) | |
| BasePetApi.subclasses = BasePetApi.subclasses + (cls,) | |
| async def add_pet( | |
| self, | |
| pet: Annotated[Pet, Field(description="Pet object that needs to be added to the store")], | |
| ) -> Pet: | |
| """""" | |
| ... |
That code is generated here, where there is no reference to {{#authMethods}} at all:
openapi-generator/modules/openapi-generator/src/main/resources/python-fastapi/base_api.mustache
Lines 17 to 23 in 98cd9bd
| {{#operation}} | |
| async def {{operationId}}( | |
| self, | |
| {{#allParams}} | |
| {{>impl_argument_definition}}, | |
| {{/allParams}} | |
| ) -> {{returnType}}{{^returnType}}None{{/returnType}}: |
As a result, it is impossible to use the validated information from the OAuth token in your implementation.
Expected behaviour
The base API should include the TokenModel:
class BasePetApi:
# ...
async def add_pet(
self,
pet: Annotated[Pet, Field(description="Pet object that needs to be added to the store")],
token_petstore_auth: TokenModel = Security(
get_token_petstore_auth, scopes=["write:pets", "read:pets"]
),
) -> Pet:
""""""
...The generated router method should pass on the TokenModel:
# ...
async def add_pet(
pet: Annotated[Pet, Field(description="Pet object that needs to be added to the store")] = Body(None, description="Pet object that needs to be added to the store"),
token_petstore_auth: TokenModel = Security(
get_token_petstore_auth, scopes=["write:pets", "read:pets"]
),
) -> Pet:
""""""
if not BasePetApi.subclasses:
raise HTTPException(status_code=500, detail="Not implemented")
return await BasePetApi.subclasses[0]().add_pet(pet, token_petstore_auth)That way, your implementation can use the token with something like:
class PetApiImpl(BasePetApi):
# ...
async def add_pet(self, pet: Pet, token_petstore_auth: TokenModel):
database.Pet.objects.create(creator=token_petstore_auth.sub, pet=pet)openapi-generator version
7.9.0
OpenAPI declaration file content or url
openapi-generator/samples/server/petstore/python-fastapi/openapi.yaml
Lines 23 to 47 in 98cd9bd
| /pet: | |
| post: | |
| description: "" | |
| operationId: addPet | |
| requestBody: | |
| $ref: '#/components/requestBodies/Pet' | |
| responses: | |
| "200": | |
| content: | |
| application/xml: | |
| schema: | |
| $ref: '#/components/schemas/Pet' | |
| application/json: | |
| schema: | |
| $ref: '#/components/schemas/Pet' | |
| description: successful operation | |
| "405": | |
| description: Invalid input | |
| security: | |
| - petstore_auth: | |
| - write:pets | |
| - read:pets | |
| summary: Add a new pet to the store | |
| tags: | |
| - pet |
Generation Details
Sample is included with OpenAPI Generator:
./bin/generate-samples.sh ./bin/configs/*.yaml