コンテンツにスキップ

api

base

ApiData

Base class to describe input/output data format on Endpoints as APIs.

Subclasses of this class can be used an argument of data_format decorator for callbacks on Endpoints. If input/output parameters of the data_format are specified, the decorator validates if raw data, typically a bytes object, has expected data format.

Subclasses of this class can define their own data formats in __init__ methods. Developers should implement __init__ methods of the subclasses such that each objects has data with expected formats by implementors.

Note

This class is an abstract class. So, don't initilize it and specify it as an argument of the data_format decorator.

Subclasses of this class should validate if raw data given to __init__ methods has expected formats. If the validation failes, the classes MUST raise ValidataionFailedError to announce the failure to the data_format decorator.

__validate__(raw, content_type) classmethod special

Parameters:

Name Type Description Default
raw bytes

Raw data to be validated.

required
content_type ContentType

Values of Content-Type header.

required
Source code in bamboo/api/base.py
@classmethod
@abstractmethod
def __validate__(cls, raw: bytes, content_type: ContentType) -> ApiData:
    """
    Args:
        raw : Raw data to be validated.
        content_type : Values of `Content-Type` header.
    """
    pass

ApiValidationFailedError

Raised if type validation of data failes.

BinaryApiData

API data with no format.

This class can be used to describe raw data with no data format. So, any received data from clients is acceptable on the class.

Examples:

class MockEndpoint(Endpoint):

    @data_format(input=BinaryApiData, output=None)
    def do_GET(self, rec_body: BinaryApiData) -> None:
        # get raw data of request body
        raw_data = rec_body.raw

raw: bytes property readonly

Raw data of input binary.

__init__(self, data) special

Parameters:

Name Type Description Default
data bytes

Binary data.

required
Source code in bamboo/api/base.py
def __init__(self, data: bytes) -> None:
    """
    Args:
        data: Binary data.
    """
    self._data = data

__validate__(raw, content_type) classmethod special

Parameters:

Name Type Description Default
raw bytes

Raw data to be validated.

required
content_type ContentType

Values of Content-Type header.

required

Returns:

Type Description
BinaryApiData

The BinaryApiData object validated succcessfully.

Note

In objects of this class, content_type is not used even if any content_type is specified.

Source code in bamboo/api/base.py
@classmethod
def __validate__(cls, raw: bytes, content_type: ContentType) -> BinaryApiData:
    """
    Args:
        raw: Raw data to be validated.
        content_type: Values of `Content-Type` header.

    Returns:
        The BinaryApiData object validated succcessfully.

    Note:
        In objects of this class, `content_type` is not used even if any
        `content_type` is specified.
    """
    if not isinstance(raw, bytes):
        raise ApiValidationFailedError(f"'raw' must be a 'bytes'.")
    return cls(raw)

form

FormApiData

API data with x-www-form-urlencoded

This class can be used to describe data with x-www-form-urlencoded format. This class should be inheritted and its several class-attributes should be defined in the subclass. Developer must define type hints of the class-attributes, which are used to validate if raw data has format the type hints define. In this class, the type hints must be only str. Otherwise, TypeError will be raised.

Examples:

  • Defining subclass of this class

    class UserCredentials(FormApiData):
        user_id: str
        password: str
    

  • Validating received data

    class MockEndpoint(Endpoint):
    
        @data_format(input=UserCredentials, output=None)
        def do_GET(self, rec_body: UserCredentials) -> None:
            # Do something...
    
            # Example
            authenticate(rec_body.user_id, rec_body.password)
    

__init__(self, **data) special

Parameters:

Name Type Description Default
raw

Raw data to be validated.

required
content_type

Values of Content-Type header.

required
Source code in bamboo/api/form.py
def __init__(self, **data: str) -> None:
    """
    Args:
        raw: Raw data to be validated.
        content_type: Values of `Content-Type` header.
    """
    mapped = _build_dict(self.__class__, **data)
    self.__dict__.update(mapped.__dict__)

__init_subclass__() classmethod special

This method is called when a class is subclassed.

The default implementation does nothing. It may be overridden to extend subclasses.

Source code in bamboo/api/form.py
def __init_subclass__(cls) -> None:
    _has_valid_annotations(cls)

__validate__(raw, content_type) classmethod special

Parameters:

Name Type Description Default
raw bytes

Raw data to be validated.

required
content_type ContentType

Values of Content-Type header.

required

Returns:

Type Description
FormApiData

The FormApiData object validated successfully.

Source code in bamboo/api/form.py
@classmethod
def __validate__(
    cls,
    raw: bytes,
    content_type: ContentType,
) -> FormApiData:
    """
    Args:
        raw: Raw data to be validated.
        content_type: Values of `Content-Type` header.

    Returns:
        The FormApiData object validated successfully.
    """
    if content_type.charset is None:
        content_type.charset = "UTF-8"

    if not cls.verify_content_type(content_type):
        raise ApiValidationFailedError(
            "Media type of 'Content-Type' header is not "
            f"{MediaTypes.x_www_form_urlencoded}, "
            f"but {content_type.media_type}."
        )

    try:
        raw = raw.decode(encoding=content_type.charset)
    except UnicodeDecodeError as e:
        raise ApiValidationFailedError(
            "Decoding raw data failed. The encoding was expected "
            f"{content_type.charset}, but not corresponded."
        ) from e
    return _build_form_api(cls, raw)

json

JsonApiData

API data with JSON format.

This class can be used to describe data with JSON format. This class should be inheritted and its several class-attributes should be defined in the subclass. Developers must define type hints of the class-attribtues, which are used to validate if raw data has format the type hints define.

Examples:

  • Defining subclass of this class

    class User(JsonApiData):
        name: str
        email: str
        age: int
    
    class MockApiData(JsonApiData):
        users: List[User]
    

  • Validating received data

    class MockEndpoint(Endpoint):
    
        @data_format(input=MockApiData, output=None)
        def do_GET(self, rec_body: MockApiData) -> None:
            # Do something...
    
            # Example
            for user in rec_body.users:
                print(f"user name : {user.name}")
    

__init_subclass__() classmethod special

This method is called when a class is subclassed.

The default implementation does nothing. It may be overridden to extend subclasses.

Source code in bamboo/api/json.py
def __init_subclass__(cls) -> None:
    _has_valid_annotations(cls)

__validate__(raw, content_type) classmethod special

Parameters:

Name Type Description Default
raw bytes

Raw data to be validated.

required
content_type ContentType

Values of Content-Type header.

required
Source code in bamboo/api/json.py
@classmethod
def __validate__(
    cls,
    raw: bytes,
    content_type: ContentType
) -> JsonApiData:
    """
    Args:
        raw: Raw data to be validated.
        content_type: Values of `Content-Type` header.
    """
    if content_type.charset is None:
        content_type.charset = "UTF-8"

    if not cls.verify_content_type(content_type):
        raise ApiValidationFailedError(
            "Media type of 'Content-Type' header was not "
            f"{MediaTypes.json}, but {content_type.media_type}."
        )

    try:
        raw = raw.decode(encoding=content_type.charset)
        data = json.loads(raw)
    except UnicodeDecodeError:
        raise ApiValidationFailedError(
            "Decoding raw data failed. The encoding was expected "
            f"{content_type.charset}, but not corresponded."
        )
    except json.decoder.JSONDecodeError:
        raise ApiValidationFailedError(
            "Decoding raw data failed."
            "The raw data had invalid JSON format."
        )
    return cls(**data)
Back to top