-
Notifications
You must be signed in to change notification settings - Fork 27
Open
Description
Description
When uploading multiple PDF files to the /api/v1/uploads endpoint, the server returns a 400 Bad Request error with the message "The browser (or proxy) sent a request that this server could not understand."
Expected Behavior
The server should accept multiple file uploads with the passwords parameter and return a 201 status code with information about the saved files.
Actual Behavior
The server receives the multipart form data correctly (as seen in the logs) but returns a 400 Bad Request error.
Code
import asyncio
import logging
from typing import List, Self
from pydantic import BaseModel, model_validator
from pydantic.dataclasses import dataclass
from quart import Blueprint, current_app, request
from quart_schema import DataSource, validate_request, validate_response
from quart_schema.pydantic import File
from library.extensions import pdf_loader
bp = Blueprint("uploads", __name__, url_prefix="/uploads")
logger = logging.getLogger(__name__)
class UploadReqst(BaseModel):
passwords: list[str] # Tried with List from typings also
documents: list[File] # Tried with List from typings also
class UploadResponse(BaseModel):
message: str
class ErrorResponse(BaseModel):
error: str
# Kept for Deubing purpose only
@bp.before_request
async def log_request():
if request.method == "POST":
form_data = await request.form
logger.debug(f"Received form data: {form_data}")
# Don't use this in production, just for debugging
files = await request.files
logger.debug(f"Received files: {files}")
@bp.route("/", methods=["POST"])
@validate_request(UploadReqst, source=DataSource.FORM_MULTIPART) # Tried with source=DataSource.MULTIPART
@validate_response(UploadResponse, 201)
async def post(data: UploadReqst) -> tuple:
logger.info(f"Total No of documents uploaded {len(data.documents)} ")
uploads_list = []
for data_item in data.documents:
logger.info(f"File name: {data_item.filename}")
uploads_list.append(pdf_loader.save(data_item, name=data_item.filename))
saved_list = await asyncio.gather(*uploads_list)
logger.info(f"Saved list: {len(saved_list)}")
return UploadResponse(message=f"Saved list: {len(saved_list)}"), 201
Response Body From Swager
<!doctype html>
<html lang=en>
<title>400 Bad Request</title>
<h1>Bad Request</h1>
<p>The browser (or proxy) sent a request that this server could not understand.</p>
Response Header From Swager
content-length: 167
content-type: text/html; charset=utf-8
date: Mon,28 Apr 2025 16:24:11 GMT
server: hypercorn-h11
x-env: DEVELOPMENT
x-language: en-US
x-timezn: UTC
x-version: 1.0.0
Server Logs
2025-04-28 16:24:11,360.360 DEBUG [MainThread] [uploads.py:36] - Received form data: ImmutableMultiDict([('passwords', 'stringzafaf')])
2025-04-28 16:24:11,360.360 DEBUG [MainThread] [uploads.py:39] - Received files: ImmutableMultiDict([('documents', <FileStorage: 'Invoice-Copy-16.pdf' ('application/pdf')>), ('documents', <FileStorage: 'Invoice_TAPL_ER_23_300.pdf' ('application/pdf')>)])
[2025-04-28 16:24:11 +0000] [5552] [INFO] 127.0.0.1:62563 POST /api/v1/uploads/ 1.1 400 167 22594
dependency
>>> import quart
>>> import quart_schema
>>> import pydantic
>>> from importlib.metadata import version
>>>
>>> print(f'quart vesrion {version("quart")}')
quart vesrion 0.20.0
>>> print(f'quart_schema vesrion {version("quart_schema")}')
quart_schema vesrion 0.22.0
>>> print(f'pydantic vesrion {version("pydantic")}')
pydantic vesrion 2.11.1
github link - https://github.com/RahulDas-dev/workflow
How to make this Work ??
Metadata
Metadata
Assignees
Labels
No labels