1

Just started learning OOP using python so I apologise if this question comes as too simplistic and welcome any improvements to my code. I am trying to write a wrapper for an API using the requests library and SurveyMonkey's API. This is what I have so far:

class SurveyMonkey:

    def __init__(self, access_token, base_url = "https://api.surveymonkey.com"):
        self.access_token = access_token
        self.base_url = base_url
        self.headers = {
            "Authorization": f"Bearer {self.access_token}",
            "Content-Type": "application/json"
        }
        self.survey_id = str()
        self.params = dict()
    
    def get_json(self):
        return requests.get(self.url, headers=self.headers, params=self.params).json()

    def list_surveys(self):
        self.url = f"{self.base_url}/v3/surveys"
        return self.get_json()

    def get_survey(self, survey_id):
        self.survey_id = survey_id
        self.url = f"{self.base_url}/v3/surveys/{self.survey_id}"
        return self.get_json()
    
    def get_survey_details(self, survey_id):
        self.survey_id = survey_id
        self.url = f"{self.base_url}/v3/surveys/{self.survey_id}/details"
        return self.get_json()
    
    def get_survey_responses_page(self, survey_id, params=dict()):
        self.survey_id = survey_id
        self.params = params
        self.url = f"{self.base_url}/v3/surveys/{self.survey_id}/responses"
        return self.get_json()
    
    def get_survey_responses_bulk_page(self, survey_id, params=dict()):
        self.survey_id = survey_id
        self.params = params
        self.url = f"{self.base_url}/v3/surveys/{self.survey_id}/responses/bulk"
        return self.get_json()
sm = SurveyMonkey(access_token)

I have used libraries where I've noticed the methods were somehow grouped. There are a few survey API's in SurveyMonkey and was wondering if I can somehow group the last 4 methods so I could call them using something like

sm.survey.get.details(id)
sm.survey.get.response.page(id)
sm.survey.get.response.bulk(id)

I couldn't really figure out how to do this

UPDATE (Thanks Tom):

I've restructured the code as per Tom's specifications and it looks like this:

class SurveyMonkey:
    
    def __init__(self, access_token, base_url = "https://api.surveymonkey.com"):
        self.surveys = surveys(self)
        self.survey_responses = survey_responses(self)
        
        self.access_token = access_token
        self.base_url = base_url
        self.headers = {
            "Authorization": f"Bearer {self.access_token}",
            "Content-Type": "application/json"
        }
        self.survey_id = str()
        self.params = dict()
        
    def get_json(self):
        return requests.get(self.url, headers=self.headers, params=self.params).json()
        
class surveys:

    def __init__(self, parent: SurveyMonkey):
        self.parent = parent

    def list_surveys(self):
        self.parent.url = f"{self.parent.base_url}/v3/surveys"
        return self.parent.get_json()
    
    def get_survey(self, survey_id):
        self.survey_id = survey_id
        self.parent.url = f"{self.parent.base_url}/v3/surveys/{self.survey_id}"
        return self.parent.get_json()
    
    def get_survey_details(self, survey_id):
        self.survey_id = survey_id
        self.parent.url = f"{self.parent.base_url}/v3/surveys/{self.survey_id}/details"
        return self.parent.get_json()
    
class survey_responses:
    
    def __init__(self, parent:SurveyMonkey):
        self.parent = parent
        
    def list_responses(self, survey_id, params=dict()):
        self.survey_id = survey_id
        self.parent.params = params
        self.parent.url = f"{self.parent.base_url}/v3/surveys/{self.survey_id}/responses"
        return self.parent.get_json()
    
    def get_response(self, survey_id, response_id, params=dict()):
        self.survey_id = survey_id
        self.response_id = response_id
        self.parent.params = params
        self.parent.url = f"{self.parent.base_url}/v3/surveys/{self.survey_id}/responses/{response_id}"
        return self.parent.get_json()
    
    def get_response_details(self, survey_id, response_id, params=dict()):
        self.survey_id = survey_id
        self.response_id = response_id
        self.parent.params = params
        self.parent.url = f"{self.parent.base_url}/v3/surveys/{self.survey_id}/responses/{response_id}/details"
        return self.parent.get_json()
    
    def get_response_bulk(self, survey_id, params=dict()):
        self.survey_id = survey_id
        self.parent.params = params
        self.parent.url = f"{self.parent.base_url}/v3/surveys/{self.survey_id}/responses/bulk"
        return self.parent.get_json()
Andrei Budaes
  • 591
  • 7
  • 22
  • 2
    You would need a `survey` attribute that iself has a `get` attribute that itself has a `details` method/function. So basically nested classes/objects. Probably not worth the effort for your small class. – timgeb Feb 03 '22 at 12:02
  • @timgeb or the cheeky way of hacking together recursive `__getatt__`/`__getattribute__` :) (which will only change the usage, not the implementation). again, does not worth it – DeepSpace Feb 03 '22 at 12:03
  • 1
    Agree with @timgeb. Not worth it for such a small class. I would personally avoid code like that. If the case is a wrapper for an API with many endpoints, i would maybe consider nesting the get/post/put methods fx. – Martin Hansen Feb 03 '22 at 12:07
  • this is just an example...the final version will have many methods hence why I wanted to group them – Andrei Budaes Feb 03 '22 at 12:56

1 Answers1

1

You can do something like this:

class SurveyMonkey:

    def __init__(self):
        self.survey = Survey(self)


class Survey:

    def __init__(self, parent: SurveyMonkey):
        self.parent = parent
        self.get = Get(self)


class Get:

    def __init__(self, parent: Survey):
        self.parent = parent
        self.response = Response(self)

    def details(self, id):
        print(id)


class Response:

    def __init__(self, parent: Get):
        self.parent = parent

    def page(self, id):
        print(id)

    def bulk(self, id):
        print(id)


sm = SurveyMonkey()
sm.survey.get.response.page(1)

Then you have to be clever about your building your request function calls, traversing the class hierarchy and building the info you need to make the request.

Tom McLean
  • 5,583
  • 1
  • 11
  • 36