]> git.ipfire.org Git - thirdparty/fastapi/fastapi.git/commitdiff
🐛 Fix JSON Schema for files, use `contentMediaType` instead of `format: binary` ...
authorSebastián Ramírez <tiangolo@gmail.com>
Sat, 21 Feb 2026 13:01:31 +0000 (05:01 -0800)
committerGitHub <noreply@github.com>
Sat, 21 Feb 2026 13:01:31 +0000 (14:01 +0100)
21 files changed:
docs/en/docs/advanced/json-base64-bytes.md [new file with mode: 0644]
docs/en/docs/img/tutorial/json-base64-bytes/image01.png [new file with mode: 0644]
docs/en/mkdocs.yml
docs_src/json_base64_bytes/__init__.py [new file with mode: 0644]
docs_src/json_base64_bytes/tutorial001_py310.py [new file with mode: 0644]
fastapi/_compat/v2.py
fastapi/datastructures.py
pyproject.toml
scripts/playwright/json_base64_bytes/image01.py [new file with mode: 0644]
tests/test_request_params/test_file/test_list.py
tests/test_request_params/test_file/test_optional.py
tests/test_request_params/test_file/test_optional_list.py
tests/test_request_params/test_file/test_required.py
tests/test_tutorial/test_json_base64_bytes/__init__.py [new file with mode: 0644]
tests/test_tutorial/test_json_base64_bytes/test_tutorial001.py [new file with mode: 0644]
tests/test_tutorial/test_request_files/test_tutorial001.py
tests/test_tutorial/test_request_files/test_tutorial001_02.py
tests/test_tutorial/test_request_files/test_tutorial001_03.py
tests/test_tutorial/test_request_files/test_tutorial002.py
tests/test_tutorial/test_request_files/test_tutorial003.py
tests/test_tutorial/test_request_forms_and_files/test_tutorial001.py

diff --git a/docs/en/docs/advanced/json-base64-bytes.md b/docs/en/docs/advanced/json-base64-bytes.md
new file mode 100644 (file)
index 0000000..c0dfec7
--- /dev/null
@@ -0,0 +1,63 @@
+# JSON with Bytes as Base64 { #json-with-bytes-as-base64 }
+
+If your app needs to receive and send JSON data, but you need to include binary data in it, you can encode it as base64.
+
+## Base64 vs Files { #base64-vs-files }
+
+Consider first if you can use [Request Files](../tutorial/request-files.md){.internal-link target=_blank} for uploading binary data and [Custom Response - FileResponse](./custom-response.md#fileresponse--fileresponse-){.internal-link target=_blank} for sending binary data, instead of encoding it in JSON.
+
+JSON can only contain UTF-8 encoded strings, so it can't contain raw bytes.
+
+Base64 can encode binary data in strings, but to do it, it needs to use more characters than the original binary data, so it would normally be less efficient than regular files.
+
+Use base64 only if you definitely need to include binary data in JSON, and you can't use files for that.
+
+## Pydantic `bytes` { #pydantic-bytes }
+
+You can declare a Pydantic model with `bytes` fields, and then use `val_json_bytes` in the model config to tell it to use base64 to *validate* input JSON data, as part of that validation it will decode the base64 string into bytes.
+
+{* ../../docs_src/json_base64_bytes/tutorial001_py310.py ln[1:9,29:35] hl[9] *}
+
+If you check the `/docs`, they will show that the field `data` expects base64 encoded bytes:
+
+<div class="screenshot">
+<img src="/img/tutorial/json-base64-bytes/image01.png">
+</div>
+
+You could send a request like:
+
+```json
+{
+    "description": "Some data",
+    "data": "aGVsbG8="
+}
+```
+
+/// tip
+
+`aGVsbG8=` is the base64 encoding of `hello`.
+
+///
+
+And then Pydantic will decode the base64 string and give you the original bytes in the `data` field of the model.
+
+You will receive a response like:
+
+```json
+{
+  "description": "Some data",
+  "content": "hello"
+}
+```
+
+## Pydantic `bytes` for Output Data { #pydantic-bytes-for-output-data }
+
+You can also use `bytes` fields with `ser_json_bytes` in the model config for output data, and Pydantic will *serialize* the bytes as base64 when generating the JSON response.
+
+{* ../../docs_src/json_base64_bytes/tutorial001_py310.py ln[1:2,12:16,29,38:41] hl[16] *}
+
+## Pydantic `bytes` for Input and Output Data { #pydantic-bytes-for-input-and-output-data }
+
+And of course, you can use the same model configured to use base64 to handle both input (*validate*) with `val_json_bytes` and output (*serialize*) with `ser_json_bytes` when receiving and sending JSON data.
+
+{* ../../docs_src/json_base64_bytes/tutorial001_py310.py ln[1:2,19:26,29,44:46] hl[23:26] *}
diff --git a/docs/en/docs/img/tutorial/json-base64-bytes/image01.png b/docs/en/docs/img/tutorial/json-base64-bytes/image01.png
new file mode 100644 (file)
index 0000000..996732b
Binary files /dev/null and b/docs/en/docs/img/tutorial/json-base64-bytes/image01.png differ
index 96ed3d58690afb4754205608df185b81aea47974..b276e55d95aad29cbe5acae5f508cb1bd31dbeef 100644 (file)
@@ -192,6 +192,7 @@ nav:
     - advanced/wsgi.md
     - advanced/generate-clients.md
     - advanced/advanced-python-types.md
+    - advanced/json-base64-bytes.md
   - fastapi-cli.md
   - Deployment:
     - deployment/index.md
diff --git a/docs_src/json_base64_bytes/__init__.py b/docs_src/json_base64_bytes/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/docs_src/json_base64_bytes/tutorial001_py310.py b/docs_src/json_base64_bytes/tutorial001_py310.py
new file mode 100644 (file)
index 0000000..3262ffb
--- /dev/null
@@ -0,0 +1,46 @@
+from fastapi import FastAPI
+from pydantic import BaseModel
+
+
+class DataInput(BaseModel):
+    description: str
+    data: bytes
+
+    model_config = {"val_json_bytes": "base64"}
+
+
+class DataOutput(BaseModel):
+    description: str
+    data: bytes
+
+    model_config = {"ser_json_bytes": "base64"}
+
+
+class DataInputOutput(BaseModel):
+    description: str
+    data: bytes
+
+    model_config = {
+        "val_json_bytes": "base64",
+        "ser_json_bytes": "base64",
+    }
+
+
+app = FastAPI()
+
+
+@app.post("/data")
+def post_data(body: DataInput):
+    content = body.data.decode("utf-8")
+    return {"description": body.description, "content": content}
+
+
+@app.get("/data")
+def get_data() -> DataOutput:
+    data = "hello".encode("utf-8")
+    return DataOutput(description="A plumbus", data=data)
+
+
+@app.post("/data-in-out")
+def post_data_in_out(body: DataInputOutput) -> DataInputOutput:
+    return body
index b83bc1b55b46709fff75ef644abd25c9a2f76540..0535c806f293d812d01a99e0be4abdd6499a698d 100644 (file)
@@ -27,7 +27,7 @@ from pydantic._internal._schema_generation_shared import (  # type: ignore[attr-
 )
 from pydantic._internal._typing_extra import eval_type_lenient
 from pydantic.fields import FieldInfo as FieldInfo
-from pydantic.json_schema import GenerateJsonSchema as GenerateJsonSchema
+from pydantic.json_schema import GenerateJsonSchema as _GenerateJsonSchema
 from pydantic.json_schema import JsonSchemaValue as JsonSchemaValue
 from pydantic_core import CoreSchema as CoreSchema
 from pydantic_core import PydanticUndefined
@@ -40,6 +40,23 @@ RequiredParam = PydanticUndefined
 Undefined = PydanticUndefined
 evaluate_forwardref = eval_type_lenient
 
+
+class GenerateJsonSchema(_GenerateJsonSchema):
+    # TODO: remove when this is merged (or equivalent): https://github.com/pydantic/pydantic/pull/12841
+    # and dropping support for any version of Pydantic before that one (so, in a very long time)
+    def bytes_schema(self, schema: CoreSchema) -> JsonSchemaValue:
+        json_schema = {"type": "string", "contentMediaType": "application/octet-stream"}
+        bytes_mode = (
+            self._config.ser_json_bytes
+            if self.mode == "serialization"
+            else self._config.val_json_bytes
+        )
+        if bytes_mode == "base64":
+            json_schema["contentEncoding"] = "base64"
+        self.update_with_validations(json_schema, schema, self.ValidationsMapping.bytes)
+        return json_schema
+
+
 # TODO: remove when dropping support for Pydantic < v2.12.3
 _Attrs = {
     "default": ...,
index c04b5f0f39feabf0fd0dd15cc0a06dab37cf491e..479e1a7c3be29cf2f30e10928aea8fad63623090 100644 (file)
@@ -139,7 +139,7 @@ class UploadFile(StarletteUploadFile):
     def __get_pydantic_json_schema__(
         cls, core_schema: Mapping[str, Any], handler: GetJsonSchemaHandler
     ) -> dict[str, Any]:
-        return {"type": "string", "format": "binary"}
+        return {"type": "string", "contentMediaType": "application/octet-stream"}
 
     @classmethod
     def __get_pydantic_core_schema__(
index 1e6fda3b1c57aac7c816bb61b287ab890f9224e3..92b47394588b6eaef5a4336ac54b556a15c1fdc7 100644 (file)
@@ -548,6 +548,7 @@ ignore = [
 "docs_src/security/tutorial005_an_py39.py" = ["B904"]
 "docs_src/security/tutorial005_py310.py" = ["B904"]
 "docs_src/security/tutorial005_py39.py" = ["B904"]
+"docs_src/json_base64_bytes/tutorial001_py310.py" = ["UP012"]
 
 [tool.ruff.lint.isort]
 known-third-party = ["fastapi", "pydantic", "starlette"]
diff --git a/scripts/playwright/json_base64_bytes/image01.py b/scripts/playwright/json_base64_bytes/image01.py
new file mode 100644 (file)
index 0000000..56c57e1
--- /dev/null
@@ -0,0 +1,37 @@
+import subprocess
+import time
+
+import httpx
+from playwright.sync_api import Playwright, sync_playwright
+
+
+# Run playwright codegen to generate the code below, copy paste the sections in run()
+def run(playwright: Playwright) -> None:
+    browser = playwright.chromium.launch(headless=False)
+    # Update the viewport manually
+    context = browser.new_context(viewport={"width": 960, "height": 1080})
+    page = context.new_page()
+    page.goto("http://localhost:8000/docs")
+    page.get_by_role("button", name="POST /data Post Data").click()
+    # Manually add the screenshot
+    page.screenshot(path="docs/en/docs/img/tutorial/json-base64-bytes/image01.png")
+
+    # ---------------------
+    context.close()
+    browser.close()
+
+
+process = subprocess.Popen(
+    ["fastapi", "run", "docs_src/json_base64_bytes/tutorial001_py310.py"]
+)
+try:
+    for _ in range(3):
+        try:
+            response = httpx.get("http://localhost:8000/docs")
+        except httpx.ConnectError:
+            time.sleep(1)
+            break
+    with sync_playwright() as playwright:
+        run(playwright)
+finally:
+    process.terminate()
index 68280fcf32a87609b60d6ba535877fac5e7d0d75..5332795f4c416a00061a3c744ae85479be469370 100644 (file)
@@ -37,7 +37,10 @@ def test_list_schema(path: str):
         "properties": {
             "p": {
                 "type": "array",
-                "items": {"type": "string", "format": "binary"},
+                "items": {
+                    "type": "string",
+                    "contentMediaType": "application/octet-stream",
+                },
                 "title": "P",
             },
         },
@@ -115,7 +118,10 @@ def test_list_alias_schema(path: str):
         "properties": {
             "p_alias": {
                 "type": "array",
-                "items": {"type": "string", "format": "binary"},
+                "items": {
+                    "type": "string",
+                    "contentMediaType": "application/octet-stream",
+                },
                 "title": "P Alias",
             },
         },
@@ -221,7 +227,10 @@ def test_list_validation_alias_schema(path: str):
         "properties": {
             "p_val_alias": {
                 "type": "array",
-                "items": {"type": "string", "format": "binary"},
+                "items": {
+                    "type": "string",
+                    "contentMediaType": "application/octet-stream",
+                },
                 "title": "P Val Alias",
             },
         },
@@ -338,7 +347,10 @@ def test_list_alias_and_validation_alias_schema(path: str):
         "properties": {
             "p_val_alias": {
                 "type": "array",
-                "items": {"type": "string", "format": "binary"},
+                "items": {
+                    "type": "string",
+                    "contentMediaType": "application/octet-stream",
+                },
                 "title": "P Val Alias",
             },
         },
index b4dc11a06aad47160cfaf2104e4705a62a90e094..3d1aac25e2b32960ba7cad681946ad3149348ff0 100644 (file)
@@ -37,7 +37,7 @@ def test_optional_schema(path: str):
         "properties": {
             "p": {
                 "anyOf": [
-                    {"type": "string", "format": "binary"},
+                    {"type": "string", "contentMediaType": "application/octet-stream"},
                     {"type": "null"},
                 ],
                 "title": "P",
@@ -109,7 +109,7 @@ def test_optional_alias_schema(path: str):
         "properties": {
             "p_alias": {
                 "anyOf": [
-                    {"type": "string", "format": "binary"},
+                    {"type": "string", "contentMediaType": "application/octet-stream"},
                     {"type": "null"},
                 ],
                 "title": "P Alias",
@@ -200,7 +200,7 @@ def test_optional_validation_alias_schema(path: str):
         "properties": {
             "p_val_alias": {
                 "anyOf": [
-                    {"type": "string", "format": "binary"},
+                    {"type": "string", "contentMediaType": "application/octet-stream"},
                     {"type": "null"},
                 ],
                 "title": "P Val Alias",
@@ -296,7 +296,7 @@ def test_optional_alias_and_validation_alias_schema(path: str):
         "properties": {
             "p_val_alias": {
                 "anyOf": [
-                    {"type": "string", "format": "binary"},
+                    {"type": "string", "contentMediaType": "application/octet-stream"},
                     {"type": "null"},
                 ],
                 "title": "P Val Alias",
index a506ec991fba61f4fc57bbf88adf0dcb5288fea9..3c211b1e8eef18288278f83102851f5af80e489d 100644 (file)
@@ -41,7 +41,10 @@ def test_optional_list_schema(path: str):
                 "anyOf": [
                     {
                         "type": "array",
-                        "items": {"type": "string", "format": "binary"},
+                        "items": {
+                            "type": "string",
+                            "contentMediaType": "application/octet-stream",
+                        },
                     },
                     {"type": "null"},
                 ],
@@ -116,7 +119,10 @@ def test_optional_list_alias_schema(path: str):
                 "anyOf": [
                     {
                         "type": "array",
-                        "items": {"type": "string", "format": "binary"},
+                        "items": {
+                            "type": "string",
+                            "contentMediaType": "application/octet-stream",
+                        },
                     },
                     {"type": "null"},
                 ],
@@ -205,7 +211,10 @@ def test_optional_validation_alias_schema(path: str):
                 "anyOf": [
                     {
                         "type": "array",
-                        "items": {"type": "string", "format": "binary"},
+                        "items": {
+                            "type": "string",
+                            "contentMediaType": "application/octet-stream",
+                        },
                     },
                     {"type": "null"},
                 ],
@@ -301,7 +310,10 @@ def test_optional_list_alias_and_validation_alias_schema(path: str):
                 "anyOf": [
                     {
                         "type": "array",
-                        "items": {"type": "string", "format": "binary"},
+                        "items": {
+                            "type": "string",
+                            "contentMediaType": "application/octet-stream",
+                        },
                     },
                     {"type": "null"},
                 ],
index a0f9d23a6bec99c020122682a575ddf29de0553d..22d6c0fffd179ab20a0305027b0cdcc08fe18fc9 100644 (file)
@@ -35,7 +35,11 @@ def test_required_schema(path: str):
 
     assert app.openapi()["components"]["schemas"][body_model_name] == {
         "properties": {
-            "p": {"title": "P", "type": "string", "format": "binary"},
+            "p": {
+                "title": "P",
+                "type": "string",
+                "contentMediaType": "application/octet-stream",
+            },
         },
         "required": ["p"],
         "title": body_model_name,
@@ -109,7 +113,11 @@ def test_required_alias_schema(path: str):
 
     assert app.openapi()["components"]["schemas"][body_model_name] == {
         "properties": {
-            "p_alias": {"title": "P Alias", "type": "string", "format": "binary"},
+            "p_alias": {
+                "title": "P Alias",
+                "type": "string",
+                "contentMediaType": "application/octet-stream",
+            },
         },
         "required": ["p_alias"],
         "title": body_model_name,
@@ -216,7 +224,7 @@ def test_required_validation_alias_schema(path: str):
             "p_val_alias": {
                 "title": "P Val Alias",
                 "type": "string",
-                "format": "binary",
+                "contentMediaType": "application/octet-stream",
             },
         },
         "required": ["p_val_alias"],
@@ -329,7 +337,7 @@ def test_required_alias_and_validation_alias_schema(path: str):
             "p_val_alias": {
                 "title": "P Val Alias",
                 "type": "string",
-                "format": "binary",
+                "contentMediaType": "application/octet-stream",
             },
         },
         "required": ["p_val_alias"],
diff --git a/tests/test_tutorial/test_json_base64_bytes/__init__.py b/tests/test_tutorial/test_json_base64_bytes/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/tests/test_tutorial/test_json_base64_bytes/test_tutorial001.py b/tests/test_tutorial/test_json_base64_bytes/test_tutorial001.py
new file mode 100644 (file)
index 0000000..4d70bca
--- /dev/null
@@ -0,0 +1,225 @@
+import importlib
+
+import pytest
+from fastapi.testclient import TestClient
+from inline_snapshot import snapshot
+
+from tests.utils import needs_py310
+
+
+@pytest.fixture(
+    name="client",
+    params=[pytest.param("tutorial001_py310", marks=needs_py310)],
+)
+def get_client(request: pytest.FixtureRequest):
+    mod = importlib.import_module(f"docs_src.json_base64_bytes.{request.param}")
+
+    client = TestClient(mod.app)
+    return client
+
+
+def test_post_data(client: TestClient):
+    response = client.post(
+        "/data",
+        json={
+            "description": "A file",
+            "data": "SGVsbG8sIFdvcmxkIQ==",
+        },
+    )
+    assert response.status_code == 200, response.text
+    assert response.json() == {"description": "A file", "content": "Hello, World!"}
+
+
+def test_get_data(client: TestClient):
+    response = client.get("/data")
+    assert response.status_code == 200, response.text
+    assert response.json() == {"description": "A plumbus", "data": "aGVsbG8="}
+
+
+def test_post_data_in_out(client: TestClient):
+    response = client.post(
+        "/data-in-out",
+        json={
+            "description": "A plumbus",
+            "data": "SGVsbG8sIFdvcmxkIQ==",
+        },
+    )
+    assert response.status_code == 200, response.text
+    assert response.json() == {
+        "description": "A plumbus",
+        "data": "SGVsbG8sIFdvcmxkIQ==",
+    }
+
+
+def test_openapi_schema(client: TestClient):
+    response = client.get("/openapi.json")
+    assert response.status_code == 200, response.text
+    assert response.json() == snapshot(
+        {
+            "openapi": "3.1.0",
+            "info": {"title": "FastAPI", "version": "0.1.0"},
+            "paths": {
+                "/data": {
+                    "get": {
+                        "summary": "Get Data",
+                        "operationId": "get_data_data_get",
+                        "responses": {
+                            "200": {
+                                "description": "Successful Response",
+                                "content": {
+                                    "application/json": {
+                                        "schema": {
+                                            "$ref": "#/components/schemas/DataOutput"
+                                        }
+                                    }
+                                },
+                            }
+                        },
+                    },
+                    "post": {
+                        "summary": "Post Data",
+                        "operationId": "post_data_data_post",
+                        "requestBody": {
+                            "content": {
+                                "application/json": {
+                                    "schema": {"$ref": "#/components/schemas/DataInput"}
+                                }
+                            },
+                            "required": True,
+                        },
+                        "responses": {
+                            "200": {
+                                "description": "Successful Response",
+                                "content": {"application/json": {"schema": {}}},
+                            },
+                            "422": {
+                                "description": "Validation Error",
+                                "content": {
+                                    "application/json": {
+                                        "schema": {
+                                            "$ref": "#/components/schemas/HTTPValidationError"
+                                        }
+                                    }
+                                },
+                            },
+                        },
+                    },
+                },
+                "/data-in-out": {
+                    "post": {
+                        "summary": "Post Data In Out",
+                        "operationId": "post_data_in_out_data_in_out_post",
+                        "requestBody": {
+                            "content": {
+                                "application/json": {
+                                    "schema": {
+                                        "$ref": "#/components/schemas/DataInputOutput"
+                                    }
+                                }
+                            },
+                            "required": True,
+                        },
+                        "responses": {
+                            "200": {
+                                "description": "Successful Response",
+                                "content": {
+                                    "application/json": {
+                                        "schema": {
+                                            "$ref": "#/components/schemas/DataInputOutput"
+                                        }
+                                    }
+                                },
+                            },
+                            "422": {
+                                "description": "Validation Error",
+                                "content": {
+                                    "application/json": {
+                                        "schema": {
+                                            "$ref": "#/components/schemas/HTTPValidationError"
+                                        }
+                                    }
+                                },
+                            },
+                        },
+                    }
+                },
+            },
+            "components": {
+                "schemas": {
+                    "DataInput": {
+                        "properties": {
+                            "description": {"type": "string", "title": "Description"},
+                            "data": {
+                                "type": "string",
+                                "contentEncoding": "base64",
+                                "contentMediaType": "application/octet-stream",
+                                "title": "Data",
+                            },
+                        },
+                        "type": "object",
+                        "required": ["description", "data"],
+                        "title": "DataInput",
+                    },
+                    "DataInputOutput": {
+                        "properties": {
+                            "description": {"type": "string", "title": "Description"},
+                            "data": {
+                                "type": "string",
+                                "contentEncoding": "base64",
+                                "contentMediaType": "application/octet-stream",
+                                "title": "Data",
+                            },
+                        },
+                        "type": "object",
+                        "required": ["description", "data"],
+                        "title": "DataInputOutput",
+                    },
+                    "DataOutput": {
+                        "properties": {
+                            "description": {"type": "string", "title": "Description"},
+                            "data": {
+                                "type": "string",
+                                "contentEncoding": "base64",
+                                "contentMediaType": "application/octet-stream",
+                                "title": "Data",
+                            },
+                        },
+                        "type": "object",
+                        "required": ["description", "data"],
+                        "title": "DataOutput",
+                    },
+                    "HTTPValidationError": {
+                        "properties": {
+                            "detail": {
+                                "items": {
+                                    "$ref": "#/components/schemas/ValidationError"
+                                },
+                                "type": "array",
+                                "title": "Detail",
+                            }
+                        },
+                        "type": "object",
+                        "title": "HTTPValidationError",
+                    },
+                    "ValidationError": {
+                        "properties": {
+                            "ctx": {"title": "Context", "type": "object"},
+                            "input": {"title": "Input"},
+                            "loc": {
+                                "items": {
+                                    "anyOf": [{"type": "string"}, {"type": "integer"}]
+                                },
+                                "type": "array",
+                                "title": "Location",
+                            },
+                            "msg": {"type": "string", "title": "Message"},
+                            "type": {"type": "string", "title": "Error Type"},
+                        },
+                        "type": "object",
+                        "required": ["loc", "msg", "type"],
+                        "title": "ValidationError",
+                    },
+                }
+            },
+        }
+    )
index 4d3c35d65dd5360b62ffe14c2b3324c91661b2ca..797225bc2d0d2f0058c02b21c0d233239050c7cc 100644 (file)
@@ -162,8 +162,8 @@ def test_openapi_schema(client: TestClient):
                         "properties": {
                             "file": {
                                 "title": "File",
+                                "contentMediaType": "application/octet-stream",
                                 "type": "string",
-                                "format": "binary",
                             }
                         },
                     },
@@ -175,7 +175,7 @@ def test_openapi_schema(client: TestClient):
                             "file": {
                                 "title": "File",
                                 "type": "string",
-                                "format": "binary",
+                                "contentMediaType": "application/octet-stream",
                             }
                         },
                     },
index f199b992aef44be9ac7227b3a5f15252c049665f..4e3c33818e98fca3c2fdc36e7edbdd6eb66b14e6 100644 (file)
@@ -134,7 +134,10 @@ def test_openapi_schema(client: TestClient):
                             "file": {
                                 "title": "File",
                                 "anyOf": [
-                                    {"type": "string", "format": "binary"},
+                                    {
+                                        "type": "string",
+                                        "contentMediaType": "application/octet-stream",
+                                    },
                                     {"type": "null"},
                                 ],
                             }
@@ -147,7 +150,10 @@ def test_openapi_schema(client: TestClient):
                             "file": {
                                 "title": "File",
                                 "anyOf": [
-                                    {"type": "string", "format": "binary"},
+                                    {
+                                        "type": "string",
+                                        "contentMediaType": "application/octet-stream",
+                                    },
                                     {"type": "null"},
                                 ],
                             }
index ce22c1b5c449f40192c3ee394bf3e7234e581664..bccc617046b8d8227166e6d49c564293418aebe6 100644 (file)
@@ -123,7 +123,7 @@ def test_openapi_schema(client: TestClient):
                                 "title": "File",
                                 "type": "string",
                                 "description": "A file read as bytes",
-                                "format": "binary",
+                                "contentMediaType": "application/octet-stream",
                             }
                         },
                     },
@@ -134,9 +134,9 @@ def test_openapi_schema(client: TestClient):
                         "properties": {
                             "file": {
                                 "title": "File",
+                                "contentMediaType": "application/octet-stream",
                                 "type": "string",
                                 "description": "A file read as UploadFile",
-                                "format": "binary",
                             }
                         },
                     },
index ebf76b3a07965954fcb7be495adce6247c1e05f6..123468d48f002b0f9cc0253d151d361295f1cd97 100644 (file)
@@ -195,7 +195,10 @@ def test_openapi_schema(client: TestClient):
                             "files": {
                                 "title": "Files",
                                 "type": "array",
-                                "items": {"type": "string", "format": "binary"},
+                                "items": {
+                                    "type": "string",
+                                    "contentMediaType": "application/octet-stream",
+                                },
                             }
                         },
                     },
@@ -207,7 +210,10 @@ def test_openapi_schema(client: TestClient):
                             "files": {
                                 "title": "Files",
                                 "type": "array",
-                                "items": {"type": "string", "format": "binary"},
+                                "items": {
+                                    "type": "string",
+                                    "contentMediaType": "application/octet-stream",
+                                },
                             }
                         },
                     },
index f11658d27c72a23f790ac01c7a04a5c272e907ee..2f554d94898e08951c2716deabf77ce4d5726bd0 100644 (file)
@@ -165,7 +165,10 @@ def test_openapi_schema(client: TestClient):
                             "files": {
                                 "title": "Files",
                                 "type": "array",
-                                "items": {"type": "string", "format": "binary"},
+                                "items": {
+                                    "type": "string",
+                                    "contentMediaType": "application/octet-stream",
+                                },
                                 "description": "Multiple files as bytes",
                             }
                         },
@@ -178,7 +181,10 @@ def test_openapi_schema(client: TestClient):
                             "files": {
                                 "title": "Files",
                                 "type": "array",
-                                "items": {"type": "string", "format": "binary"},
+                                "items": {
+                                    "type": "string",
+                                    "contentMediaType": "application/octet-stream",
+                                },
                                 "description": "Multiple files as UploadFile",
                             }
                         },
index e2462e040b971e0a9d890c5abd864560f916d895..cc10d8bec54544cdcd678561d03dc24e0d687cc8 100644 (file)
@@ -198,12 +198,12 @@ def test_openapi_schema(client: TestClient):
                             "file": {
                                 "title": "File",
                                 "type": "string",
-                                "format": "binary",
+                                "contentMediaType": "application/octet-stream",
                             },
                             "fileb": {
                                 "title": "Fileb",
+                                "contentMediaType": "application/octet-stream",
                                 "type": "string",
-                                "format": "binary",
                             },
                             "token": {"title": "Token", "type": "string"},
                         },