How can I POST data in real time using FastAPI?
Asked Answered
O

1

1

I built a simple demo project using FastAPI. I would like to POST data to the server in real time (maybe 30fps).

The client:

while True:
    ....
    res = requests.post(URL, files={'input_data' : input_data})
    ....

But, I get the following error:

(MaxRetryError: HTTPConnectionPool(host='~~', port=8000): Max retries exceeded with url)

I think it is caused due to issuing multiple requests. I would like to perform requests in real time. How can I do that?

Otherworldly answered 14/4, 2022 at 6:13 Comment(1)
Use a more suitable protocol than regular http posts; instead, use websockets (supported by FastAPI/Starlette)? fastapi.tiangolo.com/advanced/websocketsFogarty
C
3

As noted by @MatsLindh in the comments, you should rather use a more suitable protocol - such as WebSockets - than HTTP for such a task. FastAPI/Starlette supports sending and receiving data on a websocket (see the documentation here and here).

Below is a working example of using websockets to send video frames from client side to server side (assuming this is your task based on your comment on 30fps - however, the same appproach could be applied to sending other types of data). OpenCV is used to capture the frames and websockets library is used to connect to the WebSocket server. More details and examples on websockets and FastAPI can be found in this answer, on which the following example is based.

Working Example

server.py

from fastapi import FastAPI, WebSocket, WebSocketDisconnect
from websockets.exceptions import ConnectionClosed
import cv2
import numpy as np

app = FastAPI()

@app.websocket("/ws")
async def websocket_endpoint(websocket: WebSocket):
    # listen for connections
    await websocket.accept()
    #count = 1
    try:
        while True:
            contents = await websocket.receive_bytes()
            arr = np.frombuffer(contents, np.uint8)
            frame = cv2.imdecode(arr, cv2.IMREAD_UNCHANGED)
            cv2.imshow('frame', frame)
            cv2.waitKey(1)
            #cv2.imwrite("frame%d.png" % count, frame)
            #count += 1
    except (WebSocketDisconnect, ConnectionClosed):
        cv2.destroyWindow("frame")
        print("Client disconnected") 

client.py

from websockets.exceptions import ConnectionClosed
import websockets
import asyncio
import cv2

camera = cv2.VideoCapture(0, cv2.CAP_DSHOW)

async def main():
    url = 'ws://localhost:8000/ws'
    
    async for websocket in websockets.connect(url):
        try:
             while True:
                success, frame = camera.read()
                if not success:
                    break
                else:
                    ret, buffer = cv2.imencode('.png', frame)
                    await websocket.send(buffer.tobytes())
                await asyncio.sleep(0.03)
        except ConnectionClosed:
            continue  # attempt reconnecting to the server (otherwise, call break)
            
asyncio.run(main())
Calcium answered 14/4, 2022 at 12:18 Comment(4)
thank you for answer! I have a question. As in my question code, I want to get the result from the server. is it possible to use async def websocket_endpoint?Otherworldly
To return a response from the server you can use, for instance , await websocket.send_bytes(data) or await websocket.send_text(data), as documented in the links provided above. To receive the response on client side, you can use resp = await ws.recv()Calcium
is it possible to send data to client from server? I wanna get output in client from serverOtherworldly
Please have a look at this answer as well.Calcium

© 2022 - 2024 — McMap. All rights reserved.