Responses#
This notebook focuses on return information from fastapi handlers.
Check custom reponse offical documentation page.
Container for the examples in this page. Check run application for more details about image that is used for this container.
import requests
!docker run --rm -itd\
--name test_container\
-v ./responses_files/app.py:/app.py\
-p 8000:8000 \
fastapi_experiment \
uvicorn --host 0.0.0.0 --reload app:app
792aeb9776357a9802acc420ab93f47e9a74292314444831b93469b504506a85
Note Don’t forget to stop the container.
!docker stop test_container &>/dev/null
Single value types#
Consider the case when you are returning types that contain a value like int
, float
, str
and so on.
Unannotated#
APIs return value does not have to be declared.
So in the following example the output data type is not specified and the query is executed without problems.
%%writefile responses_files/app.py
from fastapi import FastAPI
app = FastAPI()
@app.get("/divide")
def divide(a: int, b: int):
return a/b
Overwriting responses_files/app.py
response = requests.get("http://localhost:8000/divide?a=10&b=2")
response.text
'5.0'
Annotated#
If you have annotated a type, you must follow it.
In the following example, the GET
response function is configured to return an int
. However, the API’s computations may result in a float
, leading to an error.
%%writefile responses_files/app.py
from fastapi import FastAPI
app = FastAPI()
@app.get("/divide")
def divide(a: int, b: int) -> int:
return a/b
Overwriting responses_files/app.py
Here is an example of API input that results in a float
data type being returned, causing the API to return an “Internal Server Error.”
response = requests.get("http://localhost:8000/divide?a=1&b=2")
response.text
'Internal Server Error'
However, if you pass values that can be unambiguously reduced to an integer, the API will return the result as an integer.
response = requests.get("http://localhost:8000/divide?a=4&b=2")
response.text
'2'
JSON#
JSON format is a popular method for transferring data over the internet. The most straightforward way to return JSON data is to pass a list
or dict
as the return
value. Find out more in the specific page.
The following cell defines an application that has both handlers that return dictionary and list.
%%writefile responses_files/app.py
from fastapi import FastAPI
app = FastAPI()
@app.get("/dict")
def return_dict():
return {
"key1": "value1",
"key2": "value2",
6: 34
}
@app.get("/list")
def return_json():
return [1, 2, 3, "hello", True]
Overwriting responses_files/app.py
Now let’s look at the results for both handlers.
display(requests.get("http://localhost:8000/list").content)
display(requests.get("http://localhost:8000/dict").content)
b'[1,2,3,"hello",true]'
b'{"key1":"value1","key2":"value2","6":34}'
Note that all keys in the dictionary have been converted to strings. So originally 6 was converted to “6”.
It’s important that we include the Content-Type: application/json
header in response headers to clearly indicate that the response body contains JSON data.
headers = requests.get("http://localhost:8000/dict").headers
for key, value in headers.items():
print(key, value)
date Tue, 20 Aug 2024 12:52:32 GMT
server uvicorn
content-length 40
content-type application/json
Pydantic models#
You can return instances of the pydantic models - it will convert the output to the corresponding Json file.
The following example shows an application that uses the pydantic model to define what a program must return.
%%writefile responses_files/app.py
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class Output(BaseModel):
a: int
b: str
@app.get("/")
def return_dict() -> Output:
return Output(a=10, b="string value")
Overwriting responses_files/app.py
response = requests.get("http://localhost:8000/")
response.text
'{"a":10,"b":"string value"}'
Exceptions#
In backend development, there are situations where you need to return messages to the user indicating errors during code execution. There are dedicated objects designed for this purpose: HTTPException
, RequestValidationError
, StarletteHTTPException
, and so on. You can even create your custom exceptions. The key feature of these objects is that you must raise them, not return them.
Check:
Handling errors official fastAPI documentation.
The following example defines an API that always raises an HTTPException
with a specified message.
%%writefile responses_files/app.py
from fastapi import FastAPI
from fastapi.exceptions import HTTPException
app = FastAPI()
@app.get("/")
def return_dict():
raise HTTPException(404, "Custom not found")
Overwriting responses_files/app.py
The following cell shows the status code and content returned from the API.
response = requests.get("http://localhost:8000")
print("Status code", response.status_code)
print("Content", response.content)
Status code 404
Content b'{"detail":"Custom not found"}'