pythonpython-requestsfastapi

Passing Integers to FastAPI post endpoint


I have two endpoints below, one that accepts two integers and another that accepts tow lists of integers.

I also have two post requests that I am making using Python requests. The request for the list of ints endpoint works fine, but the one that just accepts the two ints does not.

I know that if I pass the two ints in the URL (i.e, the query string), the endpoint will work. However, could you tell me why it doesn't work when passed as JSON?

endpoints.py

from fastapi import FastAPI

app = FastAPI()

@app.post('/ints')
def post_int(x: int, y: int):
    return x, y

@app.post('/lists')
def post_list(x: list[int], y: list[int]):
    return x, y

requests.py

import requests

r = requests.post('http://127.0.0.1:8000/ints', json={'x': 1, 'y': 2})
print(r.json()) # returns an error saying that x and y are missing

r = requests.post('http://127.0.0.1:8000/ints?x=1&y=2')
print(r.json()) # returns the two ints

r = requests.post('http://127.0.0.1:8000/lists', json={'x': [1, 2, 5], 'y': [1, 2, 3]})
print(r.json()) # returns the two lists

To start server, run "fastapi dev /path/to/endpoints.py" in terminal. Run requests.py in another terminal for output.


Solution

  • could you tell me why it doesn't work when passed as JSON?

    When you register a route with

    @app.post('/ints')
    def post_int(x: int, y: int):
        return x, y
    

    in FastApi, the route is analyzed and added in

    decorator (routing.py)
    add_api_route (routing.py)
    __init__ (routing.py)
    get_dependant (dependencies/utils.py)
    analyze_param (dependencies/utils.py)
    

    Near the end of analyze_param, you can find

    elif field_info is None and depends is None:
        default_value = value if value is not inspect.Signature.empty else RequiredParam
        if is_path_param:
            # We might check here that `default_value is RequiredParam`, but the fact is that the same
            # parameter might sometimes be a path parameter and sometimes not. See
            # `tests/test_infer_param_optionality.py` for an example.
            field_info = params.Path(annotation=use_annotation)
        elif is_uploadfile_or_nonable_uploadfile_annotation(
            type_annotation
        ) or is_uploadfile_sequence_annotation(type_annotation):
            field_info = params.File(annotation=use_annotation, default=default_value)
        elif not field_annotation_is_scalar(annotation=type_annotation):
            field_info = params.Body(annotation=use_annotation, default=default_value)
        else:
            field_info = params.Query(annotation=use_annotation, default=default_value)
    

    https://github.com/fastapi/fastapi/blob/master/fastapi/dependencies/utils.py#L460

    There you can see that scalar parameters have field info type query. Lists aren't scalar values and have field info type body.