Mas se você retornar uma Response diretamente (ou qualquer subclasse, como JSONResponse), os dados não serão convertidos automaticamente (mesmo que você declare um response_model), e a documentação não será gerada automaticamente (por exemplo, incluindo o "media type", no cabeçalho HTTP Content-Type como parte do esquema OpenAPI gerado).
Mas você também pode declarar a Response que você deseja utilizar (e.g. qualquer subclasse de Response), em um decorador de operação de rota utilizando o parâmetro response_class.
Os conteúdos que você retorna em sua função de operador de rota serão colocados dentro dessa Response.
E se a Response tiver um media type JSON (application/json), como é o caso com JSONResponse e UJSONResponse, os dados que você retornar serão automaticamente convertidos (e filtrados) com qualquer response_model do Pydantic que for declarado em sua função de operador de rota.
Nota
Se você utilizar uma classe de Resposta sem media type, o FastAPI esperará que sua resposta não tenha conteúdo, então ele não irá documentar o formato da resposta na documentação OpenAPI gerada.
Por exemplo, se você precisa bastante de performance, você pode instalar e utilizar o orjson e definir a resposta para ser uma ORJSONResponse.
Importe a classe, ou subclasse, de Response que você deseja utilizar e declare ela no decorador de operação de rota.
Para respostas grandes, retornar uma Response diretamente é muito mais rápido que retornar um dicionário.
Isso ocorre por que, por padrão, o FastAPI irá verificar cada item dentro do dicionário e garantir que ele seja serializável para JSON, utilizando o mesmoCodificador Compatível com JSON explicado no tutorial. Isso permite que você retorne objetos abstratos, como modelos do banco de dados, por exemplo.
Mas se você tem certeza que o conteúdo que você está retornando é serializável com JSON, você pode passá-lo diretamente para a classe de resposta e evitar o trabalho extra que o FastAPI teria ao passar o conteúdo pelo jsonable_encoder antes de passar para a classe de resposta.
Como visto em Retornando uma Resposta Diretamente, você também pode sobrescrever a resposta diretamente na sua operação de rota, ao retornar ela.
O mesmo exemplo de antes, retornando uma HTMLResponse, poderia parecer com:
fromfastapiimportFastAPIfromfastapi.responsesimportHTMLResponseapp=FastAPI()@app.get("/items/")asyncdefread_items():html_content=""" <html> <head> <title>Some HTML in here</title> </head> <body> <h1>Look ma! HTML!</h1> </body> </html> """returnHTMLResponse(content=html_content,status_code=200)
Aviso
Uma Response retornada diretamente em sua função de operação de rota não será documentada no OpenAPI (por exemplo, o Content-Type não será documentado) e não será visível na documentação interativa automática.
Informação
Obviamente, o cabeçalho Content-Type, o código de status, etc, virão do objeto Response que você retornou.
Se você deseja sobrescrever a resposta dentro de uma função, mas ao mesmo tempo documentar o "media type" no OpenAPI, você pode utilizar o parâmetro response_class E retornar um objeto Response.
A response_class será usada apenas para documentar o OpenAPI da operação de rota, mas sua Response será usada como foi definida.
fromfastapiimportFastAPIfromfastapi.responsesimportHTMLResponseapp=FastAPI()defgenerate_html_response():html_content=""" <html> <head> <title>Some HTML in here</title> </head> <body> <h1>Look ma! HTML!</h1> </body> </html> """returnHTMLResponse(content=html_content,status_code=200)@app.get("/items/",response_class=HTMLResponse)asyncdefread_items():returngenerate_html_response()
Neste exemplo, a função generate_html_response() já cria e retorna uma Response em vez de retornar o HTML em uma str.
Ao retornar o resultado chamando generate_html_response(), você já está retornando uma Response que irá sobrescrever o comportamento padrão do FastAPI.
Mas se você passasse uma HTMLResponse em response_class também, o FastAPI saberia como documentar isso no OpenAPI e na documentação interativa como um HTML com text/html:
Aqui estão algumas dos tipos de resposta disponíveis.
Lembre-se que você pode utilizar Response para retornar qualquer outra coisa, ou até mesmo criar uma subclasse personalizada.
Detalhes Técnicos
Você também pode utilizar from starlette.responses import HTMLResponse.
O FastAPI provê a mesma starlette.responses como fastapi.responses apenas como uma facilidade para você, desenvolvedor. Mas a maioria das respostas disponíveis vêm diretamente do Starlette.
A classe principal de respostas, todas as outras respostas herdam dela.
Você pode retorná-la diretamente.
Ela aceita os seguintes parâmetros:
content - Uma sequência de caracteres (str) ou bytes.
status_code - Um código de status HTTP do tipo int.
headers - Um dicionário dict de strings.
media_type - Uma str informando o media type. E.g. "text/html".
O FastAPI (Starlette, na verdade) irá incluir o cabeçalho Content-Length automaticamente. Ele também irá incluir o cabeçalho Content-Type, baseado no media_type e acrescentando uma codificação para tipos textuais.
fromfastapiimportFastAPI,Responseapp=FastAPI()@app.get("/legacy/")defget_legacy_data():data="""<?xml version="1.0"?> <shampoo> <Header> Apply shampoo here. </Header> <Body> You'll have to use soap here. </Body> </shampoo> """returnResponse(content=data,media_type="application/xml")
Recebe uma gerador assíncrono ou um gerador/iterador comum e retorna o corpo da requisição continuamente (stream).
fromfastapiimportFastAPIfromfastapi.responsesimportStreamingResponseapp=FastAPI()asyncdeffake_video_streamer():foriinrange(10):yieldb"some fake video bytes"@app.get("/")asyncdefmain():returnStreamingResponse(fake_video_streamer())
Utilizando StreamingResponse com objetos semelhantes a arquivos¶
Se você tiver um objeto semelhante a um arquivo (e.g. o objeto retornado por open()), você pode criar uma função geradora para iterar sobre esse objeto.
Dessa forma, você não precisa ler todo o arquivo na memória primeiro, e você pode passar essa função geradora para StreamingResponse e retorná-la.
Isso inclui muitas bibliotecas que interagem com armazenamento em nuvem, processamento de vídeos, entre outras.
Envia um arquivo de forma assíncrona e contínua (stream).
*
Recebe um conjunto de argumentos do construtor diferente dos outros tipos de resposta:
path - O caminho do arquivo que será transmitido
headers - quaisquer cabeçalhos que serão incluídos, como um dicionário.
media_type - Uma string com o media type. Se não for definida, o media type é inferido a partir do nome ou caminho do arquivo.
filename - Se for definido, é incluído no cabeçalho Content-Disposition.
Respostas de Arquivos incluem o tamanho do arquivo, data da última modificação e ETags apropriados, nos cabeçalhos Content-Length, Last-Modified e ETag, respectivamente.
Você pode criar sua própria classe de resposta, herdando de Response e usando essa nova classe.
Por exemplo, vamos supor que você queira utilizar o orjson, mas com algumas configurações personalizadas que não estão incluídas na classe ORJSONResponse.
Vamos supor também que você queira retornar um JSON indentado e formatado, então você quer utilizar a opção orjson.OPT_INDENT_2 do orjson.
Você poderia criar uma classe CustomORJSONResponse. A principal coisa a ser feita é sobrecarregar o método render da classe Response, Response.render(content), que retorna o conteúdo em bytes, para retornar o conteúdo que você deseja:
fromtypingimportAnyimportorjsonfromfastapiimportFastAPI,Responseapp=FastAPI()classCustomORJSONResponse(Response):media_type="application/json"defrender(self,content:Any)->bytes:assertorjsonisnotNone,"orjson must be installed"returnorjson.dumps(content,option=orjson.OPT_INDENT_2)@app.get("/",response_class=CustomORJSONResponse)asyncdefmain():return{"message":"Hello World"}
Agora em vez de retornar:
{"message":"Hello World"}
...essa resposta retornará:
{"message":"Hello World"}
Obviamente, você provavelmente vai encontrar maneiras muito melhores de se aproveitar disso do que a formatação de JSON. 😉