Creating a Flexible API layer in the contentcuration app in Studio
Overview
Within the contentcuration app in Studio, we want to build an API layer that acts as a communication bridge with different backends like Docker Images, Google Cloud Platform's Vertex AI, and VM instances, cloud storage services, etc. The goal is to make sure this API layer can work with these backends, regardless of where or how they do the job. As long as the input and output formats stay the same, this setup provides flexibility in choosing and using backend resources.
Description and outcomes
The stand-alone deployed backend service(s) will not have direct access to contentcuration models or the database for that matter, so this API layer facilitates access to these resources by receiving and returning a standardized requests and responses, irrespective of the backend interacted with.
The Architecture
The main components of this API layer are
Backend Interface
Adapter
Creating the Backend Interface
The core Backend class will be an abstract interface that defines the operations that all backends must support. It also implements the Singleton pattern, and provides a make_request method to forward requests to the chosen Backend, whose formats can be specified using the request and response methods.
ABSTRACT CLASS Backend:
_instance = None # Private variable to hold the instance
ABSTRACT METHOD connect()
# Provides blue print to connect
pass
ABSTRACT METHOD make_request(params)
# provide blue print to make request
pass
ABSTRACT METHOD request(params)
# provide blue print for the request object
pass
ABSTRACT METHOD response(params)
# provides blue print for the response object
pass
CLASS METHOD get_instance(cls)
IF cls._instance is None:
cls._instance = cls._create_instance()
return cls._instance
CLASS METHOD _create_instance(cls)
raise NotImplementedError # concrete class must implement
Different backends can now be created by implementing the base Backend class:
# Implement CONCRETE CLASS using ABSTRACT Backend class
CLASS GCS IMPLEMENTS Backend:
METHOD make_request(params):
# make request to Google Cloud Storage services
METHOD connect(params):
# Implement the connect method for GCS
CLASS METHOD _create_instance(cls)
# initialize a GCS Backend instance
CLASS ML IMPLEMENTS Backend:
METHOD make_request(params):
# make request to DeepLearning models hosted as service
METHOD connect(params):
# Implement the connect method for hosted ML service
CLASS METHOD _create_instance(cls)
# initialize a ML Backend instance
CLASS OtherBackend IMPLEMENTS Backend:
...
[you get the idea]
To create an instance of a backend, using the ML class as an example, use the get_instance() method:
>>> backend = ML.get_instance()
To centralize the creation of Backend instances based on specific Django settings(e.g. dev vs. production environments), create a base BackendFactory abstract class. This should follow the Factory Design Pattern.
# Abstract class for the Factory to instantiate the Backend based on Django Settings
ABSTRACT CLASS BackendFactory:
ABSTRACT METHOD create_backend(self) -> Backend
pass
The BackendFactory's create_backend method optionally allows a Backend instance to be injected into the factory instead of relying solely on Django settings. This is particularly useful if we want to explicitly specify the backend to use.
Creating Adapter that accepts any Backend
The Adapter class can be initialized with a Backend instance which provides a make_request method that forwards requests to the chosen Backend while adhering to its specific request and response formats.
CLASS Adapter:
METHOD __init__(self, backend)
# Initialize the Backend with BackendFactory
SET backend = backend
METHOD request(self):
# something
return self.backend.request()
METHOD response(self):
# something
return self.backend.response()
With this Adapter class in place, we can create Adapter that are able interact with any backend we need.
CLASS Recommendation INHERITS ADAPTER:
METHOD generateEmbeddings(self, params) -> Boolean
# [ Implementation ]
METHOD getRecommendation(self, params) -> Array
# [ Implementation ]
CLASS Transcription INHERITS ADAPTER:
METHOD generateCaption(self, params) -> Array
# [ Implementation ]
CLASS OtherAdapter INHERITS ADAPTER:
METHOD someOperation(self, params) -> Any
# Operation that any backend wants
Below is a sample use case, using the ML backend as an example:
A module with an appropriate name is created for the mini-library within the contentcuration app in Studio.
Appropriate folders are created in the created module to clearly distinguish the files(if necessary).
A base abstract Backend class that defines the operation that all backends must support is created.
The Backend class includes relevant abstract methods that allow for specific implementations for the various backends.
The Backend class implements the Singleton pattern.
A base abstract Backend Factory class that centralizes the creation of Backend instances based on Django settings is created.
All Backend instances specified in the BackendFactory follow the singleton pattern, ensuring only one instance of each backend can exist.
A base Adapter class is established, which can be initialized by any Backend.
The Adapter class includes methods that are relevant for interaction with the initialized Backend.
Tests are written to validate the correctness of the base logic implementation.
Documentation is updated to include information about the new mini-library, its usage, and its purpose.
Out of scope
This task doesn't include implementation of the the backends and adapters. They were only used to paint a picture of the architecture as a whole and how it works together.
With a considerable amount of actual development work already done by @akash5100 prior to today's iteration planning, @ozer550 has unassigned himself so Akash can proceed to complete the issue.
Creating a Flexible API layer in the
contentcuration
app in StudioOverview
Within the
contentcuration
app in Studio, we want to build an API layer that acts as a communication bridge with different backends like Docker Images, Google Cloud Platform's Vertex AI, and VM instances, cloud storage services, etc. The goal is to make sure this API layer can work with these backends, regardless of where or how they do the job. As long as the input and output formats stay the same, this setup provides flexibility in choosing and using backend resources.Description and outcomes
The stand-alone deployed backend service(s) will not have direct access to
contentcuration
models or the database for that matter, so this API layer facilitates access to these resources by receiving and returning a standardized requests and responses, irrespective of the backend interacted with.The Architecture
The main components of this API layer are
Creating the Backend Interface
The core Backend class will be an abstract interface that defines the operations that all backends must support. It also implements the Singleton pattern, and provides a
make_request
method to forward requests to the chosen Backend, whose formats can be specified using therequest
andresponse
methods.Different backends can now be created by implementing the base
Backend
class:To create an instance of a backend, using the
ML
class as an example, use theget_instance()
method:To centralize the creation of
Backend
instances based on specific Django settings(e.g. dev vs. production environments), create a baseBackendFactory
abstract class. This should follow the Factory Design Pattern.The
BackendFactory
'screate_backend
method optionally allows aBackend
instance to be injected into the factory instead of relying solely on Django settings. This is particularly useful if we want to explicitly specify the backend to use.Creating Adapter that accepts any Backend
The
Adapter
class can be initialized with aBackend
instance which provides amake_request
method that forwards requests to the chosenBackend
while adhering to its specificrequest
andresponse
formats.With this
Adapter
class in place, we can create Adapter that are able interact with any backend we need.Below is a sample use case, using the
ML
backend as an example:To access specific methods within the adapter:
Resources
OOP Design patterns
Acceptance Criteria
mini-library
within thecontentcuration
app in Studio.Backend
class that defines the operation that all backends must support is created.Backend
class includes relevant abstract methods that allow for specific implementations for the various backends.Backend
class implements the Singleton pattern.Backend Factory
class that centralizes the creation ofBackend
instances based on Django settings is created.Backend
instances specified in theBackendFactory
follow the singleton pattern, ensuring only one instance of each backend can exist.Adapter
class is established, which can be initialized by anyBackend
.Adapter
class includes methods that are relevant for interaction with the initializedBackend
.Out of scope