mirror of
https://github.com/fastapi/fastapi.git
synced 2026-02-24 02:38:13 -05:00
Compare commits
6 Commits
fix-max_di
...
0.129.1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c91fed958e | ||
|
|
04ff07fecd | ||
|
|
1bf99b9a11 | ||
|
|
e8b98d2187 | ||
|
|
d2c17b603d | ||
|
|
cf058239d1 |
2
.github/workflows/test.yml
vendored
2
.github/workflows/test.yml
vendored
@@ -45,7 +45,7 @@ jobs:
|
||||
test:
|
||||
needs:
|
||||
- changes
|
||||
if: needs.changes.outputs.src == 'true'
|
||||
if: needs.changes.outputs.src == 'true' || github.ref == 'refs/heads/master'
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ windows-latest, macos-latest ]
|
||||
|
||||
63
docs/en/docs/advanced/json-base64-bytes.md
Normal file
63
docs/en/docs/advanced/json-base64-bytes.md
Normal file
@@ -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] *}
|
||||
BIN
docs/en/docs/img/tutorial/json-base64-bytes/image01.png
Normal file
BIN
docs/en/docs/img/tutorial/json-base64-bytes/image01.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 71 KiB |
@@ -7,6 +7,12 @@ hide:
|
||||
|
||||
## Latest Changes
|
||||
|
||||
## 0.129.1
|
||||
|
||||
### Fixes
|
||||
|
||||
* ♻️ Fix JSON Schema for bytes, use `"contentMediaType": "application/octet-stream"` instead of `"format": "binary"`. PR [#14953](https://github.com/fastapi/fastapi/pull/14953) by [@tiangolo](https://github.com/tiangolo).
|
||||
|
||||
### Docs
|
||||
|
||||
* 🔨 Add Kapa.ai widget (AI chatbot). PR [#14938](https://github.com/fastapi/fastapi/pull/14938) by [@tiangolo](https://github.com/tiangolo).
|
||||
@@ -31,6 +37,7 @@ hide:
|
||||
|
||||
### Internal
|
||||
|
||||
* 👷 Always run tests on push to `master` branch and when run by scheduler. PR [#14940](https://github.com/fastapi/fastapi/pull/14940) by [@YuriiMotov](https://github.com/YuriiMotov).
|
||||
* 🎨 Upgrade typing syntax for Python 3.10. PR [#14932](https://github.com/fastapi/fastapi/pull/14932) by [@tiangolo](https://github.com/tiangolo).
|
||||
* ⬆ Bump cryptography from 46.0.4 to 46.0.5. PR [#14892](https://github.com/fastapi/fastapi/pull/14892) by [@dependabot[bot]](https://github.com/apps/dependabot).
|
||||
* ⬆ Bump pillow from 12.1.0 to 12.1.1. PR [#14899](https://github.com/fastapi/fastapi/pull/14899) by [@dependabot[bot]](https://github.com/apps/dependabot).
|
||||
|
||||
@@ -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
|
||||
|
||||
0
docs_src/json_base64_bytes/__init__.py
Normal file
0
docs_src/json_base64_bytes/__init__.py
Normal file
46
docs_src/json_base64_bytes/tutorial001_py310.py
Normal file
46
docs_src/json_base64_bytes/tutorial001_py310.py
Normal file
@@ -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
|
||||
@@ -1,6 +1,6 @@
|
||||
"""FastAPI framework, high performance, easy to learn, fast to code, ready for production"""
|
||||
|
||||
__version__ = "0.129.0"
|
||||
__version__ = "0.129.1"
|
||||
|
||||
from starlette import status as status
|
||||
|
||||
|
||||
@@ -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": ...,
|
||||
|
||||
@@ -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__(
|
||||
|
||||
@@ -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"]
|
||||
|
||||
37
scripts/playwright/json_base64_bytes/image01.py
Normal file
37
scripts/playwright/json_base64_bytes/image01.py
Normal file
@@ -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()
|
||||
@@ -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",
|
||||
},
|
||||
},
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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"},
|
||||
],
|
||||
|
||||
@@ -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"],
|
||||
|
||||
225
tests/test_tutorial/test_json_base64_bytes/test_tutorial001.py
Normal file
225
tests/test_tutorial/test_json_base64_bytes/test_tutorial001.py
Normal file
@@ -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",
|
||||
},
|
||||
}
|
||||
},
|
||||
}
|
||||
)
|
||||
@@ -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",
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
@@ -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"},
|
||||
],
|
||||
}
|
||||
|
||||
@@ -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",
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
@@ -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",
|
||||
},
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
@@ -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",
|
||||
}
|
||||
},
|
||||
|
||||
@@ -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"},
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user