samedi 29 octobre 2022

python singleton pattern request with different session for different services

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