2
\$\begingroup\$

I have an API which I want to consume in Python 3.x using the requests module. Right now, my solution is to create Requests objects for each URL like the LoginRequest, etc. (see below).

I have one request per API URL and need to write the __init__ method for each class depending on the parameters that are requested for the API. I find it tedious and I am not sure that's a good design.

Could you suggest a better design? (e.g. not using OOP, with metaclass, ... ?)

class BaseRequest:
 USER_AGENT = 'My App 1.0'
 headers = {'User-Agent': USER_AGENT}
 url = None
 data = None
 params = None
 def __init__(self, url, data=None, headers=None, params=None):
 self.url = url
 if data:
 data.update(self.data or {})
 self.data = data
 if headers:
 headers.update(self.headers or {})
 self.headers = headers
 if params:
 params.update(self.params or {})
 self.params = params
 def process(self):
 r = requests.post(self.url, data=self.data, headers=self.headers, params=self.params)
 try:
 j = r.json()
 except:
 print(self.url, self.params, self.data)
 print(r.text)
 exit()
 return j
class AuthenticatedRequest(BaseRequest):
 API_KEY = 'blah'
 APP_ID = 'OfficialClient'
 data = {'appkey': API_KEY, 'appid': APP_ID}
class LoginRequest(AuthenticatedRequest):
 url = 'https://my.api.com/login'
 def __init__(self, email, password):
 super().__init__(self.url, data=dict(email=email, password=password, action='login'))
# now let's play with the API !
user = LoginRequest(email, password).process()
GetUserInfoDetailsRequest(...).process()
Reinderien
70.9k5 gold badges76 silver badges256 bronze badges
asked Oct 29, 2015 at 16:01
\$\endgroup\$

1 Answer 1

2
\$\begingroup\$

It makes sense to model the API like this if things are more complicated, e.g. ability to pass around requests and responses as objects might come in handy.

The last example shows why this alone isn't that user-friendly though: In addition to mentioning the specific request (with the Request suffix always around) you also have to call the process method.

I'd suggest an additional wrapper to make things easier in the normal case, i.e. have login function or method that does this for you.


The code as-is looks good to me with the exception of the process method - firstly you can just write return r.json(), secondly the exit call in there is ... questionable. I most certainly wouldn't want to have a library call that on my program ever.

A minor thing I've also noticed is that the subclasses of BaseRequest can't override any values via the constructor. I'm guessing that's deliberate, I just usually expect to be able to do that (so in the base class call self.headers.update(headers) instead of the other way round).

answered Jun 30, 2016 at 9:17
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.