Design
A central feature to this client is it's detailed design, focused on a superior developer experience and performance. We also ensure that we follow design patterns outlined by Gallagher
Data Transfer Objects
This a central part of our design. There are three types of schema definitions, each one of them suffixed with their intent:
- Ref are
References
to other objects, they using contain ahref
and possibly additional meta data such as aname
orid
- Summary is what is returned by the Gallagher API in operations such as searches, these are generally a subset of the full object
- Detail are the full object found at a particular
href
, they compound on theSummary
schema and add additional attributes
I additional we have classes that defined responses which are suffixed with Response, these wrap structures which returns hrefs
for next
and previous
responses and usually have a collection to hold the response.
Ensure that each Endpoint defines their own DTOs so you can test them for authenticity. Avoid writing generic classes.
While Refs
, Summary
and Detail
responses have fields, and it would make sense from an efficiency point of view to inherit e.g Summary
builds on Ref
, this should be avoided so logically an instance of a Ref
class doesn't assert true for isinstance
of a Summary
class.
API Client Core
The core
package in cc
provides two important classes:
APIEndpoint
which all endpoint consumers configuration must inherit fromEndpointConfig
an instance of which each class must return as a result of theget_config
method
Every Endpoint Consumer Class is expected to return an instance of EndpointConfig
from the get_config
method. Each configuration provides references to paths that are dynamically discovered as part of our bootstrapping process.
Never hard code URLs as this violates the HATEOAS design principle.
Additionally each configuration will provide references to DTO classes that is used to parse responses, and details of the body.
class Alarms(
APIEndpoint
):
""" Alarms
"""
@classmethod
async def get_config(cls) -> EndpointConfig:
return EndpointConfig(
endpoint=Capabilities.CURRENT.features.alarms.alarms,
dto_list=AlarmResponse,
dto_retrieve=AlarmZoneSummary,
)
The above example shows the Alarms
class which is a consumer of the alarms
endpoint. It nominates AlarmResponse
as the class the infrastructure will use to parse list
responses and AlarmZoneSummary
as the class to parse retrieve
responses.
It references the Capabilities.CURRENT
singleton which is a Capabilities
instance that is bootstrapped at runtime. This is a singleton that is used to provide references to all endpoints.
If a command centre does not have a certain capability then the objects are set to None
and accessing the feature raises an exception (more on this in other sections).
Designing Endpoints
Layout
Layout of our files