I am using the python singleton pattern to create an API client and doing API authentication on a request session to reuse existing authentication. The current approach working fine but I need slightly change my current approach to support multiple services from the same API client. I am attaching my existing working code below-
class Singleton(type):
_instances: Dict[str, str] = {}
def __call__(cls, *args, **kwargs):
if cls not in cls._instances:
cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs)
return cls._instances[cls]
class ApiClient(metaclass=Singleton):
def __init__(self):
self._bearer_token: Optional[str] = None
self._token_expires_at: Optional[datetime] = None
self._session = requests.Session()
self.access_token_url = 'token_url'
@property
def is_client_authenticated(self) -> bool:
if not self._bearer_token or not self._token_expires_at:
return False
return datetime.now() < self._token_expires_at
@property
def session(self) -> requests.Session:
if not self.is_client_authenticated:
self.authenticate_client()
return self._session
def authenticate_client(self) -> None:
url = self.access_token_url
payload = {
"client_id": CLIENT_ID,
"client_secret": CLIENT_SECRET
}
response = self._session.post(url, data=payload)
self._bearer_token = response["access_token"]
auth_header = {"Authorization": f"Bearer {self._bearer_token}"}
self._session.headers.update(auth_header)
def get_data(self,id):
url = f"http://example.com/{id}"
params = {
"year": year,
"month": month,
}
response = self.session.get(url, params=params)
After that, I'm creating an instance of singleton ApiClient to call the existing method of the class.
service = ApiClient()
service.get_data()
But now I want to inject some variables while creating the ApiClient instance so that I can create multiple services with singleton patterns with different initialization values(Need to be sure I am using the same session for the same service because I want to reuse the session for that service.)
service_a = ApiClient(client_id_a, client_secret_a)
service_a.get_data()
and
service_b = ApiClient(client_id_b, client_secret_b)
service_b.get_data()
Note: I have the plan to modify the Singleton class to take those client_id and client_secret and create instances based on service instead of class, So I may need to modify this like below, Now I want to get any other advice or suggestion on how can I do this with fewer changes on my existing codebase.
cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs)
Aucun commentaire:
Enregistrer un commentaire