Implementation:Bentoml BentoML IO Descriptor JSON
| Knowledge Sources | |
|---|---|
| Domains | IO Descriptors, JSON Serialization, API Specification |
| Last Updated | 2026-02-13 15:00 GMT |
Overview
The JSON IO descriptor defines API specification for BentoML services that accept or return JSON data, with optional Pydantic model validation and a custom JSON encoder supporting NumPy, Pandas, dataclasses, and attrs objects.
Description
The JSON class is an IO descriptor that handles JSON-based inputs and outputs for BentoML services. It extends IODescriptor[JSONType] where JSONType is a union of str, Dict[str, Any], pydantic.BaseModel, and None. Key features include:
- Pydantic model integration: When a
pydantic_modelis provided, incoming JSON is validated and parsed into the specified Pydantic model instance. Supports both Pydantic v1 (parse_obj) and Pydantic v2 (model_validate). - Custom JSON encoder: The
DefaultJsonEncoderclass extendsjson.JSONEncoderto handle serialization ofnumpy.ndarray,numpy.generic,pandas.DataFrame,pandas.Series,pydantic.BaseModel, dataclasses, and attrs-decorated classes. - OpenAPI schema generation: Generates schemas from Pydantic models for API documentation, handling both Pydantic v1 (
model_process_schema) and v2 (model_json_schema) schema generation APIs. Produces component schemas for nested Pydantic models. - HTTP request/response handling: Parses JSON from request bodies, applies Pydantic validation if configured, and serializes responses with the configured JSON encoder.
- gRPC protobuf serialization: Converts between
google.protobuf.struct_pb2.Valuemessages and JSON types usingParseDictandMessageToDict. The helper functionparse_dict_to_protohandles conversion of both standard types and custom objects via the JSON encoder. - Pydantic version compatibility: Explicitly checks
pkg_version_info("pydantic")to branch between v1 and v2 APIs throughout the codebase.
Usage
Use this descriptor when building BentoML services that accept structured JSON input, especially when you want schema validation through Pydantic models. It is specified as the input or output parameter in the @svc.api decorator.
Code Reference
Source Location
- Repository: Bentoml_BentoML
- File: src/bentoml/_internal/io_descriptors/json.py
- Lines: 1-497
Signature
class JSON(
IODescriptor[JSONType],
descriptor_id="bentoml.io.JSON",
proto_fields=("json",),
):
def __init__(
self,
*,
pydantic_model: type[pydantic.BaseModel] | None = None,
validate_json: bool | None = None,
json_encoder: type[json.JSONEncoder] = DefaultJsonEncoder,
): ...
def _from_sample(self, sample: JSONType) -> JSONType: ...
def to_spec(self) -> dict[str, t.Any]: ...
@classmethod
def from_spec(cls, spec: dict[str, t.Any]) -> Self: ...
def input_type(self) -> UnionType: ...
def openapi_schema(self) -> Schema: ...
def openapi_components(self) -> dict[str, t.Any] | None: ...
def openapi_example(self): ...
def openapi_request_body(self) -> dict[str, t.Any]: ...
def openapi_responses(self) -> OpenAPIResponse: ...
async def from_http_request(self, request: Request) -> JSONType: ...
async def to_http_response(self, obj: JSONType | pydantic.BaseModel, ctx: Context | None = None): ...
async def from_proto(self, field: struct_pb2.Value | bytes) -> JSONType: ...
async def to_proto(self, obj: JSONType) -> struct_pb2.Value: ...
class DefaultJsonEncoder(json.JSONEncoder):
def default(self, o: type) -> t.Any: ...
def parse_dict_to_proto(
obj: JSONType,
msg: _message.Message,
json_encoder: type[json.JSONEncoder] = DefaultJsonEncoder,
) -> t.Any: ...
Import
from bentoml.io import JSON
I/O Contract
Inputs
| Name | Type | Required | Description |
|---|---|---|---|
| pydantic_model | type[pydantic.BaseModel] or None | No | Pydantic model class for input validation and schema generation. When set, incoming JSON is parsed into an instance of this model. |
| validate_json | bool or None | No | Deprecated option. A warning is logged if provided. |
| json_encoder | type[json.JSONEncoder] | No | Custom JSON encoder class. Defaults to DefaultJsonEncoder which handles numpy, pandas, dataclass, and attrs objects. |
Outputs
| Name | Type | Description |
|---|---|---|
| JSONType | str, Dict[str, Any], pydantic.BaseModel, or None | The deserialized JSON object from an incoming request, or the object to serialize for a response. |
Usage Examples
from __future__ import annotations
import bentoml
from bentoml.io import JSON, NumpyNdarray
from pydantic import BaseModel
import pandas as pd
from typing import Optional, Any
class IrisFeatures(BaseModel):
sepal_len: float
sepal_width: float
petal_len: float
petal_width: float
request_id: Optional[int] = None
class Config:
extra = "forbid"
runner = bentoml.sklearn.get("iris_clf_with_feature_names:latest").to_runner()
svc = bentoml.legacy.Service("iris_classifier_pydantic", runners=[runner])
input_spec = JSON(pydantic_model=IrisFeatures)
@svc.api(input=input_spec, output=NumpyNdarray())
def classify(input_data: IrisFeatures) -> Any:
input_df = pd.DataFrame([input_data.dict(exclude={"request_id"})])
return runner.run(input_df)
# Using from_sample with a plain dictionary
input_spec2 = JSON.from_sample({"hello": "world", "foo": "bar"})
@svc.api(input=input_spec2, output=JSON())
async def echo(input_data: dict[str, Any]) -> dict[str, Any]:
return input_data