Requests#

There are numerous ways to organize requests to an application.

from fastapi import FastAPI
from fastapi.testclient import TestClient

from pydantic import BaseModel
from datetime import datetime, timedelta

Syntax options#

Here, we consider different options for configuring endpoint syntax.

Query params#

In order to pass an argument using ulr we need to write a construction ?param1=argument1&param2=argument2&...&paramN=argumentN at the end of url (in web development, the name for this construction is query params).


The following example shows api to divide two numbers and use the syntax /divide?a=10&b=2 in the url to complete the division.

app = FastAPI()

@app.get("/divide")
def divide(a: int, b: int) -> int:
    return a/b

test_client = TestClient(app=app)
display(test_client.get("/divide?a=10&b=2").content)
test_client.close()
b'5'

You can specify default values by defining them as the default values for the parameters in the corresponding Python function.

app = FastAPI()

@app.get("/divide")
def divide(a: int, b: int=10) -> int:
    return a/b

test_client = TestClient(app=app)
display(test_client.get("/divide?a=20").content)
test_client.close()
b'2'

Path params#

You can specify some parameters as part of your url. Just specify url in fastapi decorators using the syntax <path>/{param1}/{param2}/.... So you can request this api by using the corresponding syntax.


In the next cell, an application is defined that will use path parameter syntax for a division API.

app = FastAPI()

@app.get("/divide/{a}/{b}")
def divide(a: int, b: int) -> float:
    return a/b

test_client = TestClient(app=app)
display(test_client.get("/divide/10/2").content)
test_client.close()
b'5.0'

Pydantic model#

You can define pydentic model as an input to your endpoint - simply by declaring pydentic model as a type in parameters.


So the following fastapi program defines Item which expects json with keys param1 and param2 and just returns line describing what data we’ve got.

class Item(BaseModel):
    param1: int
    param2: str

app = FastAPI()

@app.post("/")
def read_json(item: Item):
    return f"""I have got:
    param1={item.param1};
    param2={item.param2}."""

test_client = TestClient(app=app)
data = {"param1" : 2, "param2": "test line"}
print(
    test_client.post(url="/", json=data)
    .content.decode("utf-8").replace("\\n", "\n")
)
test_client.close()
"I have got:
    param1=2;
    param2=test line."

Data types#

You need to declare data types for the arguments otherwise the call will not work correctly.


The following example describes a programme without input datatypes. The request to the server causes the error:

app = FastAPI()

@app.get("/divide")
def divide(a, b) -> int:
    return f"{a} {b}"

test_client = TestClient(app=app)

try:
    display(test_client.get("/divide?a=10&b=2").content)
except Exception as e:
    print(e)

test_client.close()
1 validation errors:
  {'type': 'int_parsing', 'loc': ('response',), 'msg': 'Input should be a valid integer, unable to parse string as an integer', 'input': '10 2'}

Datetime input#

You are allowed to use datetime.datetime as input type in fastapi. But note that you have to use ISO 8601 fromat for datetime objects - <YYYY-MM-DDTHH-MM-SS>. Where:

  • YYYYY: year (e.g. 2022);

  • MM: month (from 01 to 12);

  • DD: day (from 01 to 31);

  • T: separator between date and time;

  • HH: hour (00 to 23);

  • MM: minutes (from 00 to 59);

  • SS: seconds (00 to 59).


The following example is the service that takes any date and returns the date for the next day:

app = FastAPI()

@app.get("/add_year")
def add_year(dt : datetime):
    return dt + timedelta(days = 1)

test_client = TestClient(app=app)
display(test_client.get("/add_year?dt=2022-10-05T20:10:10").content)
test_client.close()
b'"2022-10-06T20:10:10"'

Request object#

In your FastAPI application, you can work with a special type of object called Request. This object contains various technical details about the incoming request to your application.

For more check:


The following code demonstrates how to access the Request object in your endpoint. Simply add a parameter with the type fastapi.Request to your function, and FastAPI will pass the request object to that parameter. The example code returns the host of the client that sent the request, which can be obtained using request.client.host.

from fastapi import Request

app = FastAPI()

@app.get("/")
def index(request: Request):
    return request.client.host

The following cell runs the application using the TestClient utility.

test_client = TestClient(app=app)
display(test_client.get("http://localhost:8000").content)
test_client.close()
b'"testclient"'

As a result, the API returned testclient—this seems to be a feature of FastAPI.

Additionally, consider executing the application using httpx.AsyncClient:

from httpx import AsyncClient

async with AsyncClient(app=app, base_url="http://hello") as ac:
    print(((await ac.get("/")).content))
b'"127.0.0.1"'

Now it returns the localhost IP address, which is correct because we are calling the API from the same host it was launched on.