diff --git a/litestar/_openapi/path_item.py b/litestar/_openapi/path_item.py index de48e906a3..30a1f5ad02 100644 --- a/litestar/_openapi/path_item.py +++ b/litestar/_openapi/path_item.py @@ -62,12 +62,17 @@ def create_operation_for_handler_method( signature_fields = route_handler.parsed_fn_signature.parameters request_body = None + request_body_field = None if data_field := signature_fields.get("data"): request_body = create_request_body( self.context, route_handler.handler_id, route_handler.data_dto, data_field ) + request_body_field = data_field + elif body_field := signature_fields.get("body"): + request_body = create_request_body(self.context, route_handler.handler_id, None, body_field) + request_body_field = body_field - raises_validation_error = bool(data_field or self._path_item.parameters or parameters) + raises_validation_error = bool(request_body_field or self._path_item.parameters or parameters) responses = create_responses_for_handler( self.context, route_handler, raises_validation_error=raises_validation_error ) diff --git a/litestar/_openapi/request_body.py b/litestar/_openapi/request_body.py index 7a5cf37de5..3dd6187554 100644 --- a/litestar/_openapi/request_body.py +++ b/litestar/_openapi/request_body.py @@ -34,7 +34,9 @@ def create_request_body( Returns: A RequestBody instance. """ - media_type: RequestEncodingType | str = RequestEncodingType.JSON + media_type: RequestEncodingType | str = ( + "application/octet-stream" if data_field.is_subclass_of(bytes) else RequestEncodingType.JSON + ) schema_creator = SchemaCreator.from_openapi_context(context, prefer_alias=True) if isinstance(data_field.kwarg_definition, BodyKwarg) and data_field.kwarg_definition.media_type: media_type = data_field.kwarg_definition.media_type diff --git a/tests/unit/test_openapi/test_request_body.py b/tests/unit/test_openapi/test_request_body.py index 0badda8ac2..de6528d98b 100644 --- a/tests/unit/test_openapi/test_request_body.py +++ b/tests/unit/test_openapi/test_request_body.py @@ -217,3 +217,69 @@ async def handler( } } } + + +def test_body_parameter_binary_request() -> None: + @post("/upload/") + async def handle_binary_upload(body: bytes) -> None: + return None + + app = Litestar([handle_binary_upload]) + schema = app.openapi_schema.to_schema() + + assert "requestBody" in schema["paths"]["/upload"]["post"] + assert schema["paths"]["/upload"]["post"]["requestBody"] == { + "required": True, + "content": {"application/octet-stream": {"schema": {"type": "string"}}}, + } + + +def test_body_parameter_with_body_annotation() -> None: + @post("/upload/") + async def handle_binary_upload( + body: Annotated[bytes, Body(media_type="application/octet-stream", title="Binary Data")], + ) -> None: + return None + + app = Litestar([handle_binary_upload]) + schema = app.openapi_schema.to_schema() + + assert "requestBody" in schema["paths"]["/upload"]["post"] + assert schema["paths"]["/upload"]["post"]["requestBody"] == { + "required": True, + "content": {"application/octet-stream": {"schema": {"type": "string", "title": "Binary Data"}}}, + } + + +def test_body_parameter_with_default_value() -> None: + @post("/upload/") + async def handle_binary_upload( + body: bytes = Body(media_type="application/octet-stream", title="Binary Data"), + ) -> None: + return None + + app = Litestar([handle_binary_upload]) + schema = app.openapi_schema.to_schema() + + assert "requestBody" in schema["paths"]["/upload"]["post"] + assert schema["paths"]["/upload"]["post"]["requestBody"] == { + "required": True, + "content": {"application/octet-stream": {"schema": {"type": "string", "title": "Binary Data"}}}, + } + + +def test_body_parameter_with_custom_media_type() -> None: + @post("/upload/") + async def handle_binary_upload( + body: Annotated[bytes, Body(media_type="application/x-custom-binary")], + ) -> None: + return None + + app = Litestar([handle_binary_upload]) + schema = app.openapi_schema.to_schema() + + assert "requestBody" in schema["paths"]["/upload"]["post"] + assert schema["paths"]["/upload"]["post"]["requestBody"] == { + "required": True, + "content": {"application/x-custom-binary": {"schema": {"type": "string"}}}, + }