0

been driving me crazy with the syntax for the past week, so hopefully an enlightened one can point me out! I've traced these posts, but somehow I couldn't get them to work

I am looking to have an input variable where it is a list, and a numpy array; for feeding into a fastAPI get function, and then calling it via a request.get. Somehow, I cannot get the arguments/syntax correct.

FastAPI POST request with List input raises 422 Unprocessable Entity error

Can FastAPI/Pydantic individually validate input items in a list?

I have the following web API defined :

import typing
from typing import List
from fastapi import Query
from fastapi import FastAPI

 @appOne.get("/sabr/funcThree")
        def funcThree(x1: List[float], x2: np.ndarray):
            return {"x1" : x1, "x2" : x2}

Then, I try to call the function from a jupyter notebook:

import requests
url_ = "http://127.0.0.1:8000/sabr/"
func_ = "funcThree"

items = [1, 2, 3, 4, 5]

params = {"x1" : items, "x2" : np.array([3,100])}
print(url_ + func_)
requests.get(url_ + func_, params = params).json()

I get the following error below...

{'detail': [{'loc': ['body', 'x1'],
   'msg': 'field required',
   'type': 'value_error.missing'}]}

It's driving me CRAZY .... Help!!!!


though answered in the above, as it is a related question..... I put a little update.

I add in a 'type_' field, so that it can return different type of results. But somehow, the json= params is NOT picking it up. Below is the python fastAPI code :

@app.get("/sabr/calib_test2")
    def calib_test2(x1: List[float] = [1, 2, 3], x2: List[float] = [4, 5, 6]\
,  type_: int = 1):
        s1 = np.array(x1)
        s2 = np.array(x2)
        # corr = np.corrcoef(x1, x2)[0][1]
        if type_ == 1:
            return {"x1": x1, "x1_sum": s1.sum(), "x2": x2, \
"x2_sum": s2.sum(), "size_x1": s1.shape}
        elif type_ == 2:
            return ['test', x1, s1.sum(), x2, s2.sum(), s1.shape]
        else:
            return [0, 0, 0]

But, it seems somehow the type_ input I am keying in, is NOT being fed-through... Help...

url_ = "http://127.0.0.1:8000/sabr/"
func_ = "calib_test2"
item1 = [1, 2, 3, 4, 5]
item2 = [4, 5, 6, 7, 8]

all_ = url_ + func_
params = {"x1": item1, "x2": item2, "type_": '2', "type_": 2}
resp = requests.get(all_, json = params)
# resp.raise_for_status()
resp.json()

Results keep being :

{'x1': [1.0, 2.0, 3.0, 4.0, 5.0],
 'x1_sum': 15.0,
 'x2': [4.0, 5.0, 6.0, 7.0, 8.0],
 'x2_sum': 30.0,
 'size_x1': [5]}
Kiann
  • 531
  • 1
  • 6
  • 20
  • 2
    There is no native HTTP serialization for a Numpy array. Also, a 3x100 array could easily be longer than the maximum query string length supported by various parts of the HTTP stack; a POST request would be better. – AKX Mar 02 '23 at 13:00
  • Does this answer your question? [How to pass string and multiple files using FastAPI and Python requests?](https://stackoverflow.com/questions/73981953/how-to-pass-string-and-multiple-files-using-fastapi-and-python-requests) – Chris Mar 02 '23 at 13:14
  • Please have a look at Option 2 of [this answer](https://stackoverflow.com/a/73982479/17865804), as well as [this answer](https://stackoverflow.com/a/71427592/17865804) (which you cited in your question). As described in both the answers, one has to define the `List` parameter explicitly with `Query` (e.g., `= Query(...)`), in order to be expected as query and not body parameter; hence the error that _"'**body**', 'x1' required field is missing"_. Related answers can be found [here](https://stackoverflow.com/a/70845425/17865804) and [here](https://stackoverflow.com/a/73067473/17865804) as well. – Chris Mar 02 '23 at 13:17
  • thanks. I did read through, and kind of managed to get the 'List' working. The numpy array is still failing, though – Kiann Mar 02 '23 at 15:05
  • How to pass string and multiple files using FastAPI and Python requests? -> @Chris, I mean the broad 'syntax' is there, but it does not show directly the 'List' and 'numpy' form. I had been trying for a whole day to adapt the answer, but ... haiz... kept failing.......... – Kiann Mar 02 '23 at 15:09
  • The linked answers provided earlier were all related to the error included in the question. As for the numpy array, option 2 of [this answer](https://stackoverflow.com/a/71639658/17865804), as well as [this answer](https://stackoverflow.com/a/71265664/17865804) and [this answer](https://stackoverflow.com/a/71104203/17865804) will point you in the right direction. I would also suggest using a `POST` request instead of a `GET` one, having the data sent in the request body rather than the query string. – Chris Mar 02 '23 at 17:13

1 Answers1

0

You can't use a Numpy array directly as a data format. If you're looking to ingest a 2D numpy array, you'll

  • need to use POST (there's no good way to represent a 2D array as a query paremeter)
  • need to cast a list-of-lists back to a numpy array

so the server side ends up looking like

from typing import List

import numpy as np
from fastapi import FastAPI

app = FastAPI()


@app.post("/sabr")
def sabr(x1: List[float], x2: List[List[float]]):
    s = np.array(x2)
    return {"x1": x1, "x2": s.sum(), "size": s.shape}

and on the client side, you'll need to tolist the numpy array and POST it as JSON:

import numpy as np
import requests

url = "http://127.0.0.1:8000/sabr"
items = [1, 2, 3, 4, 5]
params = {
    "x1": items,
    "x2": np.random.randint(0, 100, size=[3, 100]).tolist(),
}
resp = requests.post(url, json=params)
resp.raise_for_status()
print(resp.json())

This outputs (e.g., since it's random)

{'x1': [1.0, 2.0, 3.0, 4.0, 5.0], 'x2': 15320.0, 'size': [3, 100]}
AKX
  • 152,115
  • 15
  • 115
  • 172