I have a web application in which I want to support different incoming APIs, but business logic of processing requests is the same for all of the incoming APIs.
Right now business logic works with a single implemented API and works directly with gunicorn's Request
class.
In order for business logic to not rely on the format of incoming http requests / or how data is received in general, to reduce code duplication, to not implement different functions which do the same but on different fields, in other words, to keep it dry, the common interface were implemented which is used by business logic for data access, for e.g.
class IMyAppRequest(Request):
def __init__(self):
self._username = None
self._address = None
@property
def username(self):
raise
@property
def address(self):
raise
And classes which implement this interface dynamically calculating username
and address
fields.
class TypeARequest(IMyAppRequest):
@property
def address(self):
if self._address is not None:
return self._address
self._address = self.body["geolocation"]["addr"]
return self._address
class TypeBRequest(IMyAppRequest):
@property
def address(self):
if self._address is not None:
return self._address
self._address = self.body["country"]["city"]["full_address"]
return self._address
And now I want to implement a middleware which wraps/replaces incoming gunicorn's Request
with classes above.
How do you properly do it? Basically, I want drop-in replacement of a parent class with child one. I can't instantiate child class initially because I have to have a full http request parsed before I can determine which type it is. Networking/request parsing incorporated in gunicorn's Request
class itself, so the Request
class is already created while the request is not parsed.
I can't go with simple inheritance because it won't solve the issue. Right now i'm using a dependency injection(?):
class IMyAppRequest:
def __init__(self, http_request):
self.request = http_request
self._username = None
self._address = None
@property
def username(self):
raise
@property
def address(self):
raise
def __getattr__(self, item):
return getattr(self.request, item)
def __setattr(self, key, value):
return setattr(self.request, key, value)
where http_request
is gunicorn's Request
instance.
That way I can simply wrap the request in middleware depending on request's type. But is it how you do it? Or it's completely wrong? I couldn't find something related in source codes of libraries I'm using/python stdlib, and I can't trust myself in this question that this implementation is ok.
Aucun commentaire:
Enregistrer un commentaire