I am trying to pass a value called 'ethAddress' from an input form on the client to FastAPI so that I can use it in a function to generate a matplotlib chart.
I am using fetch to POST the inputted text in Charts.tsx file:
fetch("http://localhost:8000/ethAddress", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(ethAddress),
}).then(fetchEthAddresses);
Then I have my api.py file set up as follows:
#imports
app = FastAPI()
@app.get("/ethAddress")
async def get_images(background_tasks: BackgroundTasks, ethAddress: str):
image = EthBalanceTracker.get_transactions(ethAddress)
img_buf = image
background_tasks.add_task(img_buf.close)
headers = {'Content-Disposition': 'inline; filename="out.png"'}
return Response(img_buf.getvalue(), headers=headers, media_type='image/png')
@app.post("/ethAddress")
async def add_ethAddress(ethAddress: str):
return ethAddress
To my understanding, I am passing the 'ethAddress' in the Request Body from the client to the backend using fetch
POST
request, where I then have access to the value that has been posted using @app.post
in FastAPI. I then return that value as a string. Then I am using it in the GET
route to generate the chart.
I'm getting this error:
INFO: 127.0.0.1:59821 - "POST /ethAddress HTTP/1.1" 422 Unprocessable Entity
INFO: 127.0.0.1:59821 - "GET /ethAddress HTTP/1.1" 422 Unprocessable Entity
I have also tried switching the fetch method on the client to GET instead of POST. But get the following error:
TypeError: Failed to execute 'fetch' on 'Window': Request with GET/HEAD method cannot have body.
The way you defined ethAddress
in your endpoint is expected as a query parameter; hence, the 422 Unprocessable Entity
error. As per the documentation:
When you declare other function parameters that are not part of the path parameters, they are automatically interpreted as "query" parameters.
For the parameter to be interpreted as JSON, you would need to use one of the following options.
Create a Pydantic model:
from pydantic import BaseModel
class Item(BaseModel):
eth_addr: str
@app.post('/')
async def add_eth_addr(item: Item):
return item
FastAPI will expect a body like:
{
"eth_addr": "some addr"
}
Perform HTTP request using Fetch API:
fetch('/', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify({
"eth_addr": "some addr"
}),
})
.then(resp => resp.json()) // or, resp.text(), etc.
.then(data => {
console.log(data); // handle response data
})
.catch(error => {
console.error(error);
});
Use the Body
parameter type:
from fastapi import Body
@app.post('/')
async def add_eth_addr(eth_addr: str = Body()):
return {'eth_addr': eth_addr}
FastAPI will expect a body like:
"some addr"
Perform HTTP request using Fetch API:
fetch('/', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify("some addr"),
})
.then(resp => resp.json()) // or, resp.text(), etc.
.then(data => {
console.log(data); // handle response data
})
.catch(error => {
console.error(error);
});
Since you have a single body parameter, you might want to use the special Body
parameter embed
:
from fastapi import Body
@app.post('/')
async def add_eth_addr(eth_addr: str = Body(embed=True)):
return {'eth_addr': eth_addr}
FastAPI will expect a body like:
{
"eth_addr": "some addr"
}
Perform HTTP request using Fetch API:
fetch('/', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify({
"eth_addr": "some addr"
}),
})
.then(resp => resp.json()) // or, resp.text(), etc.
.then(data => {
console.log(data); // handle response data
})
.catch(error => {
console.error(error);
});
Related answers, including JavaScript examples on how to post JSON data, can be found here, here, as well as here and here. This answer might also prove helpful as well, when it comes to posting both JSON data and Files in the same request.