'How to send and receive data in XML format using WebSockets and FastAPI?

I'm trying to communicate with a fingerprint device. Actaully it sends data through websocket connection. So, I think I can communicate with the device using webscokets. Here I'm using FastAPI, but it only accepts JSON data. The problem is that I need to handle XML data, however, I do not know how to send and accept data in XML format.



Solution 1:[1]

FastAPI can accept and validate other types of data as well, not only JSON as you stated. Have a look at the documentation. Regarding XML, as FastAPI is actually Starlette underneath, you can use Starlette's request object directly to read the request body as bytes, and return a custom Response with the XML data (if required). You can check if the incoming request is of the required Content-Type, and if so, let it through; otherwise, you could raise an HTTPException. Below is a working example using Python requests on client side and a normal HTTP endpoint on server side.

Using HTTP Protocol

app.py

from fastapi import FastAPI, Response, Request, HTTPException

app = FastAPI()

@app.post("/submit")
async def submit(request: Request):
    content_type = request.headers['Content-Type']
    if content_type == 'application/xml':
        body = await request.body()
        return Response(content=body, media_type="application/xml")
    else:
        raise HTTPException(status_code=400, detail=f'Content type {content_type} not supported')

test.py

import requests

body = """<?xml version='1.0' encoding='utf-8'?><a>?</a>"""
headers = {'Content-Type': 'application/xml'}
url = 'http://127.0.0.1:8000/submit'
r = requests.post(url, data=body.encode('utf-8'), headers=headers)
print(r.content)

In websockets, you can use send_bytes() and receive_bytes() for the communication, as described in Starlette's documentation, allowing you to send and receive (byte encoded) XML data as well. If you would like to perform validation on the received XML data, have a look at this answer.

Using WebSocket Protocol

app.py

from fastapi import FastAPI, Request, WebSocket, WebSocketDisconnect
import uvicorn

app = FastAPI()

@app.websocket("/ws")
async def get_stream(websocket: WebSocket):
    await websocket.accept()
    try:
        while True:
            contents = await websocket.receive_bytes()
            print(str(contents, 'utf-8'))
    except WebSocketDisconnect:
        print("Client disconnected")   
 
if __name__ == '__main__':
    uvicorn.run(app, host='127.0.0.1', port=8000)

test.py

import websockets
import asyncio

async def main():
    url = 'ws://127.0.0.1:8000/ws'
    
    async with websockets.connect(url) as ws:
         while True:
            b = bytes("<?xml version='1.0' encoding='utf-8'?><a>?</a>", 'utf-8')
            await ws.send(b)
            await asyncio.sleep(1)
            
asyncio.run(main())

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1