Home  >  Article  >  Backend Development  >  How to Create a FastAPI Endpoint That Accepts Either Form or JSON Body?

How to Create a FastAPI Endpoint That Accepts Either Form or JSON Body?

DDD
DDDOriginal
2024-10-27 06:16:03482browse

How to Create a FastAPI Endpoint That Accepts Either Form or JSON Body?

How to create a FastAPI endpoint that can accept either Form or JSON body?

In FastAPI, you can define endpoints that handle various types of request bodies, such as JSON or form-data. This allows you to create endpoints that can accept either format without the need for separate endpoints.

To achieve this, you can follow one of the below approaches:

Option 1: Using a dependency function

You can utilize a dependency function to verify the request's Content-Type header, then parse the body appropriately using Starlette's methods. Note that relying solely on the Content-Type header may not always guarantee the validity of the request body, so it's recommended to include error handling.

<code class="python">import os, sys
from fastapi import FastAPI, Depends, HTTPException
from starlette.requests import Request
app = FastAPI()

# Generating file
open("./app.txt", "w").write("hello from a file")

async def body_parser(request: Request):
    ct = request.headers.get("Content-Type", "")
    if ct == "application/json":
        try:
            d = await request.json()
            if not isinstance(d, dict):
                raise HTTPException(status_code=400, details={"error":"request body must be a dict"})
            return d
        except JSONDecodeError:
            raise HTTPException(400, "Could not parse request body as JSON")
    elif ct == "multipart/form-data":
        await request.stream()  # this is required for body parsing.
        d = await request.form()
        if not d:
            raise HTTPException(status_code=400, details={"error":"no form parameters found"})
        return d
    else:
        raise HTTPException(405, "Content-Type must be either JSON or multipart/form-data")

@app.post("/", dependencies=[Depends(body_parser)])
async def body_handler(d: dict):
    if "file" in d:
        return {"file": d["file"]}
    return d</code>

Option 2: Utilizing optional form/file parameters

In this approach, you can define form/file parameters as optional in your endpoint. If any of these parameters have values, it assumes a form-data request. Otherwise, it validates the request body as JSON.

<code class="python">from fastapi import FastAPI, Form, File, UploadFile
app = FastAPI()

@app.post("/")
async def file_or_json(
    files: List[UploadFile] = File(None),
    some_data: str = Form(None)
):
    if files:
        return {"files": len(files)}
    return {"data": some_data}</code>

Option 3: Defining separate endpoints for each type

You can also create separate endpoints, one for JSON and another for form-data. Using a middleware, you can check the Content-Type header and reroute the request to the appropriate endpoint.

<code class="python">from fastapi import FastAPI, Request, Form, File, UploadFile
from fastapi.responses import JSONResponse
app = FastAPI()

@app.middleware("http")
async def middleware(request: Request, call_next):
    ct = request.headers.get("Content-Type", "")
    if ct == "application/json":
        request.scope["path"] = "/json"
    elif ct in ["multipart/form-data", "application/x-www-form-urlencoded"]:
        request.scope["path"] = "/form"
    return await call_next(request)

@app.post("/json")
async def json_endpoint(json_data: dict):
    pass

@app.post("/form")
async def form_endpoint(file: UploadFile = File(...)):
    pass</code>

Option 4: Referencing another answer for an alternative approach

Additionally, you may find this answer on Stack Overflow helpful as it provides a different perspective on handling both JSON and form-data in a single endpoint:

https://stackoverflow.com/a/67003163/10811840

Testing Options 1, 2, & 3

For testing purposes, you can use requests library:

<code class="python">import requests

url = "http://127.0.0.1:8000"
# for testing Python 3.7 and above use:
# url = "http://localhost:8000"

# form-data request
files = [('files', ('a.txt', open('a.txt', 'rb'), 'text/plain'))]
response = requests.post(url, files=files)
print(response.text)

# JSON request
data = {"some_data": "Hello, world!"}
response = requests.post(url, json=data)
print(response.text)</code>

These approaches provide different methods to create an endpoint that can handle both JSON and form-data in FastAPI. Choose the approach that best fits your requirements and use case.

The above is the detailed content of How to Create a FastAPI Endpoint That Accepts Either Form or JSON Body?. For more information, please follow other related articles on the PHP Chinese website!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn