#How to return 413 or 415 status from POST

1 messages · Page 1 of 1 (latest)

bleak gust
#

How do I return either 413 or 415 for:

@post(path="/upload")
async def handle_file_upload(
    data: Annotated[UploadFile, Body(media_type=RequestEncodingType.MULTI_PART)],
) -> dict[str, Any]:

  content = await data.read()

  if len(content)>1024:
    # return 415

  # if content is not particular filetype
  #   return 413

  # this returns 201
  return {
    "filename": data.filename
    "content_length": len(content)
  }

Thanks in advance!

mellow lanceBOT
#
Notes for How to return 413 or 415 status from POST
At your assistance

@bleak gust

No Response?

If no response in a reasonable time, ping @Member.

Closing

To close, type !solve or byte solve.

MCVE

Please include an MCVE so that we can reproduce your issue locally.

silent elm
#

you may return Response class with ur status code

bleak gust
#

Like this?

from pydantic import BaseModel
from litestar import Litestar, MediaType, post, status_codes

class Resource(BaseModel):
    filename: str
    content_length: int
    status_code: int

@post(path="/upload")
async def handle_file_upload(
    data: Annotated[UploadFile, Body(media_type=RequestEncodingType.MULTI_PART)],
) -> Resource
  
  content = await data.read()

  return Resource(
        filename=data.filename, content_length=len(content), status_code=status_codes.HTTP_413_REQUEST_ENTITY_TOO_LARGE
    )

still returns 201

silent elm
#

i don't see any issues

#
from dataclasses import dataclass
from typing import Any

from litestar import Litestar, post
from litestar.openapi import OpenAPIConfig
from litestar.openapi.datastructures import ResponseSpec
from litestar.openapi.plugins import ScalarRenderPlugin
from litestar.response import Response
from litestar.status_codes import (
    HTTP_200_OK,
    HTTP_400_BAD_REQUEST,
    HTTP_404_NOT_FOUND,
    HTTP_500_INTERNAL_SERVER_ERROR,
)
from pydantic import BaseModel


# Response Schemas
class SuccessResponse(BaseModel):
    message: str


class ErrorResponse(BaseModel):
    error: str


@dataclass
class StatusResponse:
    message: str | None = None
    error: str | None = None
#
@post(
    "/status/{code:int}",
    responses={
        HTTP_200_OK: ResponseSpec(data_container=StatusResponse, description="Success response"),
        HTTP_400_BAD_REQUEST: ResponseSpec(data_container=StatusResponse, description="Bad request error"),
        HTTP_404_NOT_FOUND: ResponseSpec(data_container=StatusResponse, description="Resource not found"),
        HTTP_500_INTERNAL_SERVER_ERROR: ResponseSpec(
            data_container=StatusResponse, description="Internal server error"
        ),
    },
)
async def status_by_code(code: int) -> Response[Any]:
    """Return different HTTP status codes based on the path parameter."""
    if code == HTTP_200_OK:
        return Response(StatusResponse(message="Success!"), status_code=HTTP_200_OK)
    if code == HTTP_400_BAD_REQUEST:
        return Response(StatusResponse(error="Bad request"), status_code=HTTP_400_BAD_REQUEST)
    if code == HTTP_404_NOT_FOUND:
        return Response(StatusResponse(error="Not found"), status_code=HTTP_404_NOT_FOUND)
    if code == HTTP_500_INTERNAL_SERVER_ERROR:
        return Response(StatusResponse(error="Server error"), status_code=HTTP_500_INTERNAL_SERVER_ERROR)
    return Response(StatusResponse(error="Unknown code"), status_code=code)


app = Litestar(
    [status_by_code],
    openapi_config=OpenAPIConfig(
        title="HTTP Status Code POC",
        version="1.0.0",
        path="/schema",
        render_plugins=[ScalarRenderPlugin()],
    ),
)


if __name__ == "__main__":
    import uvicorn

    uvicorn.run(app, host="127.0.0.1", port=8000)
#

wait why you returning Resource instead of Response

bleak gust
#
from dataclasses import dataclass
from typing import Annotated, Any

from litestar import Litestar, post, status_codes
from litestar.datastructures import UploadFile
from litestar.enums import RequestEncodingType
from litestar.params import Body
from litestar.response import Response

@dataclass
class ErrorResponse:
    message: str | None = None
    error: str | None = None
 
@dataclass
class FileUploadResponse:
    filename: str | None = None
    content_length: int = 0

@post(path="/upload")
async def handle_file_upload(
    data: Annotated[UploadFile, Body(media_type=RequestEncodingType.MULTI_PART)],
) -> Response[Any]:
    content = await data.read()

    # figure out content_type from content
    
    if content_type != "application/pdf":
        return Response(
            ErrorResponse(
                message="Upload failed", error="Filetype must be application/pdf"
            ),
            status_code=status_codes.HTTP_415_UNSUPPORTED_MEDIA_TYPE,
        )

    if len(content) > MAX_CONTENT_LEN:
        return Response(
            ErrorResponse(
                message="Upload failed", error="Content length exceeded",
            ),
            status_code=status_codes.HTTP_413_REQUEST_ENTITY_TOO_LARGE,
        )

    # Success - do something with content

    return Response(
        FileUploadResponse(filename=data.filename, content_length=len(content))
    )

app = Litestar(route_handlers=[handle_file_upload])

Thanks for your code, it was a bit confusing but ultimately helpful.
I've posted my own pared down version, any comments are welcome.
Thanks!

silent elm
#

haha i generated poc code using claude,to ensure that openapi parse correctly so i include the full one