class_docstr: :obj:`JSON` defines API specification for the inputs/outputs of a Service, where either
  inputs will be converted to or outputs will be converted from a JSON representation
  as specified in your API function signature.
  
  A sample service implementation:
  
  .. code-block:: python
     :caption: `service.py`
  
     from __future__ import annotations
  
     import typing
     from typing import TYPE_CHECKING
     from typing import Any
     from typing import Optional
  
     import bentoml
     from bentoml.io import NumpyNdarray
     from bentoml.io import JSON
  
     import numpy as np
     import pandas as pd
     from pydantic import BaseModel
  
     iris_clf_runner = bentoml.sklearn.get("iris_clf_with_feature_names:latest").to_runner()
  
     svc = bentoml.Service("iris_classifier_pydantic", runners=[iris_clf_runner])
  
     class IrisFeatures(BaseModel):
         sepal_len: float
         sepal_width: float
         petal_len: float
         petal_width: float
  
         # Optional field
         request_id: Optional[int]
  
         # Use custom Pydantic config for additional validation options
         class Config:
             extra = 'forbid'
  
  
     input_spec = JSON(pydantic_model=IrisFeatures)
  
     @svc.api(input=input_spec, output=NumpyNdarray())
     def classify(input_data: IrisFeatures) -> NDArray[Any]:
         if input_data.request_id is not None:
             print("Received request ID: ", input_data.request_id)
  
         input_df = pd.DataFrame([input_data.dict(exclude={"request_id"})])
         return iris_clf_runner.run(input_df)
  
  Users then can then serve this service with :code:`bentoml serve`:
  
  .. code-block:: bash
  
      % bentoml serve ./service.py:svc --reload
  
  Users can then send requests to the newly started services with any client:
  
  .. tab-set::
  
      .. tab-item:: Bash
  
          .. code-block:: bash
  
             % curl -X POST -H "content-type: application/json" \
                 --data '{"sepal_len": 6.2, "sepal_width": 3.2, "petal_len": 5.2, "petal_width": 2.2}' \
                 http://127.0.0.1:3000/classify
  
             # [2]%
  
      .. tab-item:: Python
  
          .. code-block:: python
             :caption: `request.py`
  
              import requests
  
              requests.post(
                  "http://0.0.0.0:3000/predict",
                  headers={"content-type": "application/json"},
                  data='{"sepal_len": 6.2, "sepal_width": 3.2, "petal_len": 5.2, "petal_width": 2.2}'
              ).text
  
  Args:
      pydantic_model: Pydantic model schema. When used, inference API callback
                      will receive an instance of the specified ``pydantic_model`` class.
      json_encoder: JSON encoder class. By default BentoML implements a custom JSON encoder that
                    provides additional serialization supports for numpy arrays, pandas dataframes,
                    dataclass-like (`attrs <https://www.attrs.org/en/stable/>`_, dataclass, etc.).
                    If you wish to use a custom encoder, make sure to support the aforementioned object.
  
  Returns:
      :obj:`JSON`: IO Descriptor that represents JSON format.
code: def from_spec(cls, spec: dict[str, t.Any]) -> Self:
      if "args" not in spec:
          raise InvalidArgument(
              f"Missing args key in JSON spec: {spec}"
          )
      if (
          "has_pydantic_model" in spec["args"]
          and spec["args"]["has_pydantic_model"]
      ):
          logger.warning(
              "BentoML does not support loading pydantic models from URLs; output will be a normal dictionary."
          )
      if (
          "has_json_encoder" in spec["args"]
          and spec["args"]["has_json_encoder"]
      ):
          logger.warning(
              "BentoML does not support loading JSON encoders from URLs; output will be a normal dictionary."
          )
  
      return cls()
  
imports: from __future__ import annotations
  import dataclasses
  import json
  import logging
  import typing
  import attr
  from starlette.requests import Request
  from starlette.responses import Response
  from ...exceptions import BadInput
  from ...exceptions import InvalidArgument
  from ..service.openapi import REF_PREFIX
  from ..service.openapi import SUCCESS_DESCRIPTION
  from ..service.openapi.specification import MediaType
  from ..service.openapi.specification import Schema
  from ..types import LazyType
  from ..utils import LazyLoader
  from ..utils import bentoml_cattr
  from ..utils.http import set_cookies
  from ..utils.pkg import pkg_version_info
  from .base import IODescriptor
label_desc: Use image node_id 4 for calling the JSON obj's underlying member method code with example usage: obj.from_spec(cls, spec) and returns: cls