Reimplement how we return responses
Currently we return responses from the various functions as ad-hoc custom classes which are dynamically created based on what we get from the API.
I think this needs to be improved. Look at other SDKs and see what they do and see if we can adopt it.
TBD
SDK Return Types
- mobolic/facebook-sdk Functions in this SDK mostly return dictionaries decoded from JSONs like so:
try:
response = self.session.request(
method or "GET",
FACEBOOK_GRAPH_URL + path,
timeout=self.timeout,
params=args,
data=post_args,
proxies=self.proxies,
files=files)
except requests.HTTPError as e:
response = json.loads(e.read())
raise GraphAPIError(response)
This is similar to some of our SDK functions that do not wrap the return values in a class.
- Azure/azure-sdk-for-python
The Azure sdk is really large and has a lot of modules, but follow a consistent structure throughout the codebase. Each module contains a
models/folder, which contains classes inherited from a baseModelclass and contain a dictionary named_attribute_map, which contains the data fetched from their api. API results are wrapped inside these Model classes. Each module also has anoperations/folder, which containOperations()classes. These classes are made according to responsibility, and contain methods that are relevant to their respective functions . Request data are serialized before sending to the server, and deserialized into the appropriateModelbefore returning to the user. They also haverawflags for returning results in raw JSON format.
if response.status_code == 200:
deserialized = self._deserialize('RecordSet', response)
if raw:
client_raw_response = ClientRawResponse(deserialized, response)
return client_raw_response
return deserialized
- boto/boto3 a.k.a. AWS SDK for Python
Boto3 also uses
Modelclasses that provide a layer of abstraction from raw JSON. These classes are used to createResourceclasses by theResourceFactory. One model that is most relevant to is theResourceModel, which is used to contain data and to represent a resource. Example Model:
class ResourceModel(object):
"""
A model representing a resource, defined via a JSON description
format. A resource has identifiers, attributes, actions,
sub-resources, references and collections. For more information
on resources, see :ref:`guide_resources`.
:type name: string
:param name: The name of this resource, e.g. ``sqs`` or ``Queue``
:type definition: dict
:param definition: The JSON definition
:type resource_defs: dict
:param resource_defs: All resources defined in the service
"""
Creating resources from resource models using the ResourceFactory class:
class ResourceFactory(object):
"""
A factory to create new :py:class:`~boto3.resources.base.ServiceResource`
classes from a :py:class:`~boto3.resources.model.ResourceModel`. There are
two types of lookups that can be done: one on the service itself (e.g. an
SQS resource) and another on models contained within the service (e.g. an
SQS Queue resource).
"""
def load_from_definition(self, resource_name,
single_resource_json_definition, service_context):
...
...
resource_model = ResourceModel(
resource_name, single_resource_json_definition,
service_context.resource_json_definitions
)
...
...
# Load attributes into the resource model
self._load_attributes(
attrs=attrs, meta=meta, resource_name=resource_name,
resource_model=resource_model,
service_context=service_context)
...
This kind of structure may not be the best for our SDK because we do not have a lot of Model types to benefit from this kind of abstraction. Having Models to abstract away JSON types are good enough for our use case and would allow for easier developing.