Base64 にしたバイトを含む JSON¶
🌐 AI と人間による翻訳
この翻訳は、人間のガイドに基づいて AI によって作成されました。🤝
原文の意図を取り違えていたり、不自然な表現になっている可能性があります。🤖
AI LLM をより適切に誘導するのを手伝う ことで、この翻訳を改善できます。
アプリで JSON データの受信・送信が必要だが、その中にバイナリデータを含める必要がある場合は、base64 にエンコードできます。
Base64 とファイル¶
バイナリデータのアップロードにはまず、JSON にエンコードする代わりに Request Files を、バイナリデータの送信には カスタムレスポンス - FileResponse を使えるか検討してください。
JSON は UTF-8 でエンコードされた文字列のみを含められるため、生のバイト列は含められません。
Base64 はバイナリデータを文字列にエンコードできますが、そのために元のバイナリより多くの文字を使用する必要があり、通常は通常のファイルより非効率です。
JSON にバイナリデータをどうしても含める必要があり、ファイルを使えない場合にのみ base64 を使用してください。
Pydantic bytes¶
Pydantic モデルで bytes 型のフィールドを宣言し、モデル設定で val_json_bytes を使うと、入力 JSON データの検証時に base64 を用いるよう指示できます。この検証の一環として、base64 文字列はバイト列へデコードされます。
from fastapi import FastAPI
from pydantic import BaseModel
class DataInput(BaseModel):
description: str
data: bytes
model_config = {"val_json_bytes": "base64"}
# Code here omitted 👈
app = FastAPI()
@app.post("/data")
def post_data(body: DataInput):
content = body.data.decode("utf-8")
return {"description": body.description, "content": content}
# Code below omitted 👇
👀 Full file preview
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
「/docs」を確認すると、data フィールドが base64 でエンコードされたバイト列を期待していることが表示されます。
次のようなリクエストを送れます:
{
"description": "Some data",
"data": "aGVsbG8="
}
豆知識
aGVsbG8= は hello の base64 エンコードです。
その後、Pydantic は base64 文字列をデコードし、モデルの data フィールドに元のバイト列を渡します。
次のようなレスポンスを受け取ります:
{
"description": "Some data",
"content": "hello"
}
出力データ向けの Pydantic bytes¶
出力データ用にモデル設定で ser_json_bytes とともに bytes フィールドを使用することもでき、Pydantic は JSON レスポンスを生成するときにバイト列を base64 でシリアライズします。
from fastapi import FastAPI
from pydantic import BaseModel
# Code here omitted 👈
class DataOutput(BaseModel):
description: str
data: bytes
model_config = {"ser_json_bytes": "base64"}
# Code here omitted 👈
app = FastAPI()
# Code here omitted 👈
@app.get("/data")
def get_data() -> DataOutput:
data = "hello".encode("utf-8")
return DataOutput(description="A plumbus", data=data)
# Code below omitted 👇
👀 Full file preview
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
入力・出力データ向けの Pydantic bytes¶
もちろん、同じモデルを base64 を使うように設定しておけば、JSON データの受信時は val_json_bytes で入力を「検証」し、送信時は ser_json_bytes で出力を「シリアライズ」する、といった具合に、入力と出力の両方を扱えます。
from fastapi import FastAPI
from pydantic import BaseModel
# Code here omitted 👈
class DataInputOutput(BaseModel):
description: str
data: bytes
model_config = {
"val_json_bytes": "base64",
"ser_json_bytes": "base64",
}
# Code here omitted 👈
app = FastAPI()
# Code here omitted 👈
@app.post("/data-in-out")
def post_data_in_out(body: DataInputOutput) -> DataInputOutput:
return body
👀 Full file preview
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