Skip to content

Base64 JSON file inputs

Use the x-speakeasy-base64-input-mode extension to let a JSON string field accept binary IO streams or filesystem paths in addition to a pre-encoded base64 string. The generated SDK base64-encodes non-string inputs at request construction time and the wire payload is always a JSON string.

Supported languages

Implemented for Python only. Other targets currently ignore the extension.

Add x-speakeasy-base64-input-mode: file to a JSON string property marked as base64 — either format: byte (OpenAPI 3.0+) or contentEncoding: base64 (OpenAPI 3.1+). Without the extension, the field remains a plain str.

properties:
dataByte:
type: string
format: byte
x-speakeasy-base64-input-mode: file
dataContentEncoding:
type: string
contentEncoding: base64
x-speakeasy-base64-input-mode: file

Opted-in fields are typed as Base64EncodedString, a pydantic alias that runs a BeforeValidator to convert non-string inputs to a base64 string before storage.

from os import PathLike
from typing import IO, Union
Base64FileInput = Union[IO[bytes], PathLike[str]]
Base64EncodedString = Annotated[str, BeforeValidator(encode_base64_file_input)]

The encode_base64_file_input validator accepts:

  • A PathLike value — the file at that path is read in binary mode and base64-encoded.
  • A binary IO object (any io.IOBase returning bytes) — the stream is read and base64-encoded.
  • A str — passed through unchanged (treated as already encoded).

Any other value raises a TypeError.

The generated request model exposes the field as a plain str after validation, so downstream attribute reads remain statically typed as str even when the same component is reused on the response side.

class Base64InputFileModeRequest(BaseModel):
data_byte: Annotated[Base64EncodedString, pydantic.Field(alias="dataByte")]
data_content_encoding: Annotated[
Base64EncodedString, pydantic.Field(alias="dataContentEncoding")
]

SDK methods accept the wider input union at the call site:

def post_base64_input_mode(
self,
*,
data_byte: Union[Base64EncodedString, Union[str, Base64FileInput]],
data_content_encoding: Union[Base64EncodedString, Union[str, Base64FileInput]],
) -> models.operations.PostBase64InputModeResponse:
...
# filesystem path
sdk.post_base64_input_mode(
data_byte=Path("./payload.bin"),
data_content_encoding="dGVzdA==",
)
# open binary stream
with open("./payload.bin", "rb") as fh:
sdk.post_base64_input_mode(data_byte=fh, data_content_encoding=fh)
# pre-encoded base64 string
sdk.post_base64_input_mode(data_byte="dGVzdA==", data_content_encoding="dGVzdA==")
  • Python (pythonv2) only.
  • Accepted non-string inputs are restricted to Union[IO[bytes], os.PathLike]. bytes and bytearray literals are not auto-encoded; encode them with base64.b64encode(...).decode("ascii") before passing them in.
  • Generated SDK methods emit # type: ignore[arg-type] at the request construction site to bridge the wider method-argument union (Union[str, Base64FileInput]) and the declared field type (str). At runtime the BeforeValidator converts the value before the str validator runs, so the suppression is aligned with sound runtime behavior.
  • Schema components reused across request and response leak the wider input union into the response-side TypedDict. A hand-built response literal will type-check with BytesIO/PathLike even though the wire only ever carries a str. Prefer BaseModel attribute access on responses, which stays typed as str.