@tiangolo does FastAPI support serialization / parsing of pydantic models with custom root types? If not, would you be interested in supporting it? It seems like serialization could be accomplished with a minimal change to jsonable_encoder to look for
__root__
, and parsing through the use ofparse_obj
(not sure if that is used for parsing yet).
@dmontagu , @euri10 __root__
is useful for people using Pydantic alone, but as @euri10 says, in FastAPI it doesn't provide any advantage. response_model
and any FastAPI path operation parameter are not interpreted as just Pydantic models, but Pydantic Fields. (Pydantic's Field
class). So, they can take anything that a Pydantic model attribute can take, any Python type (including Pydantic models).
you can watch how I integrated alembic here @ebreton https://gitlab.com/euri10/euri10_fastapi_base/blob/master/backend/app/migrations/env.py#L31
that's nice :star2: thanks @euri10 ! With regards to nested objects and missing SQLalchemy ORM, how have you handled that ? I can see in your example that user_settings have a relationship to users, but it doesn't look like you are making use of it in the code
Hi, I'm very new to FastAPI. Thanks for your work! I am trying to handle a 302 to allow the user to complete an OAuth authorization. I have tried returning the response from the Python requests library, which is indeed a 302, directly to the browser, but I get an exception. It seems that FastAPI is trying to look inside of the response, rather than just passing it along. How can I resolve this?
DEBUG:main:login response: <Response [302]>
INFO:uvicorn:('67.191.210.63', 58131) - "GET /login HTTP/1.1" 500
ERROR:uvicorn:Exception in ASGI application
Traceback (most recent call last):
File "/usr/local/lib/python3.7/site-packages/uvicorn/protocols/http/httptools_impl.py", line 368, in run_asgi
result = await app(self.scope, self.receive, self.send)
File "/usr/local/lib/python3.7/site-packages/engineio/async_drivers/asgi.py", line 53, in call
await self.other_asgi_app(scope, receive, send)
File "/usr/local/lib/python3.7/site-packages/starlette/applications.py", line 133, in call
await self.error_middleware(scope, receive, send)
File "/usr/local/lib/python3.7/site-packages/starlette/middleware/errors.py", line 122, in call
raise exc from None
File "/usr/local/lib/python3.7/site-packages/starlette/middleware/errors.py", line 100, in call
await self.app(scope, receive, _send)
File "/usr/local/lib/python3.7/site-packages/starlette/exceptions.py", line 73, in call
raise exc from None
File "/usr/local/lib/python3.7/site-packages/starlette/exceptions.py", line 62, in call
await self.app(scope, receive, sender)
File "/usr/local/lib/python3.7/site-packages/starlette/routing.py", line 585, in call
await route(scope, receive, send)
File "/usr/local/lib/python3.7/site-packages/starlette/routing.py", line 207, in call
await self.app(scope, receive, send)
File "/usr/local/lib/python3.7/site-packages/starlette/routing.py", line 40, in app
response = await func(request)
File "/usr/local/lib/python3.7/site-packages/fastapi/routing.py", line 122, in app
skip_defaults=response_model_skip_defaults,
File "/usr/local/lib/python3.7/site-packages/fastapi/routing.py", line 63, in serialize_response
return jsonable_encoder(response)
File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 110, in jsonable_encoder
sqlalchemy_safe=sqlalchemy_safe,
File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 66, in jsonable_encoder
sqlalchemy_safe=sqlalchemy_safe,
File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 110, in jsonable_encoder
sqlalchemy_safe=sqlalchemy_safe,
File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 66, in jsonable_encoder
sqlalchemy_safe=sqlalchemy_safe,
File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 110, in jsonable_encoder
sqlalchemy_safe=sqlalchemy_safe,
File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 66, in jsonable_encoder
sqlalchemy_safe=sqlalchemy_safe,
File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 110, in jsonable_encoder
sqlalchemy_safe=sqlalchemy_safe,
File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 66, in jsonable_encoder
sqlalchemy_safe=sqlalchemy_safe,
File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 103, in jsonable_encoder
raise ValueError(errors)
ValueError: [KeyError(<class 'object'>), TypeError("'object' object is not iterable"), TypeError('vars() argument must have dict attribute')]
def login(response: Response):
resp = getAuthCode()
response.status_code = 302
response.headers['Location'] = resp.headers['Location']
logger.debug(f'login response: {response}')
return response
Are you getting your roles from the JWT token? a db user query? Did you want to do it as a decorator? You’ll need to add role access control logic to each endpoint you want to protect.
A db query, probably. I was hoping for an existing solution in the starlette world, to be honest.
Are you getting your roles from the JWT token? a db user query? Did you want to do it as a decorator? You’ll need to add role access control logic to each endpoint you want to protect.
Hi @wshayes getting roles/claims from a JWT token is a super interesting topic for me but I’m curious what is your suggestion
current_user: User = Depends(get_current_active_user))
when using app.add_route for graphql?
So in my api I'm returning a pydantic model, and fastAPI is converting it to json. If I test or demonstrate a endpoint directly via the browser (rather than through docs), is there a way to get FastAPI to prettyprint (indent) the json?
it's already the case @nrshapiro the returned json is indented, see this screen for instance:
dict(skip_defaults=True)
You can add any fields you want to a JWT payload. I’ve seen tokens that have several dozen fields and are around 4kb in size - I think that’s a bit overdoing it :) It’s not a problem from the JWT spec/browsers/servers - just adds more IO to each request.
Thanks @wshayes, my first thought is to find a viable solution to receive authorization claims/roles from an external authentication system and spend it over a microservices architecture based on FastAPI
starlette.responses.JSONResponse
) looks like this: class JSONResponse(Response):
media_type = "application/json"
def render(self, content: typing.Any) -> bytes:
return json.dumps(
content,
ensure_ascii=False,
allow_nan=False,
indent=None,
separators=(",", ":"),
).encode("utf-8")
indent=4
and separators=(", ", ": ")
in json.dumps
I think it will render closer to the "pretty" way
import json
import typing
from starlette.responses import Response
class PrettyJSONResponse(Response):
media_type = "application/json"
def render(self, content: typing.Any) -> bytes:
return json.dumps(
content,
ensure_ascii=False,
allow_nan=False,
indent=4,
separators=(", ", ": "),
).encode("utf-8")
@app.get("/", response_class=PrettyJSONResponse)
async def get_some_json():
...