2
\$\begingroup\$

I'm looking to create a wrapper for an API, mainly for learning purposes at work as "The IT guy". I've been trying to follow the PEP 8 styling guide and make my docstring as detailed as possible.

I believe my code looks quite sluggish. I've tried to avoid duplicate code and multiple line sets of logic.

Here's my class initialization:

class API:
    def __init__(self, environment, client_code, api_key):
        """ __init__()

            Instantiate an instance of API.

            Parameters:
        environment(string): The runtime environment. Acceptable arguements [sandbox] [live]
        client_code(string): Your client code, found the settings page of your account
                api_key(string): The API key found in the settings page of your account
        """
        self.base_url = 'https://%s.apiprovider.co.uk/api/v3/client/%s/' %\
                        (environment, client_code)

        self.header = {
            'Accept': 'json',
            'apiKey': api_key,
            'Content-Type': 'json',
            'Content-Length': '0'
        }

    # Pythonic names | API names
        self.customer_arguments = {
            'customer_ref': 'customerRef',
            'email': 'email',
            'title': 'title',
            'first_name': 'firstName',
            'surname': 'surname',
            'post_code': 'postCode',
            'line1': 'line1',
            'line2': 'line2',
            'account_number': 'accountNumber',
            'sort_code': 'bankSortCode',
            'account_name': 'accountHolderName',
            'date_of_birth': 'dateOfBirth',
            'company_name': 'companyName',
            'home_phone': 'homePhone',
            'work_phone': 'workPhone',
            'mobile_phone': 'mobilePhone',
            'line3': 'line3',
            'line4': 'line4',
            'initials': 'initials'
        }

        self.session = requests.Session()

And an example class definition:

def create_customer(self, customer_ref, email, first_name,
                    surname, post_code, line1, account_number,
                    sort_code, account_name, **keyword_arguments):

    """ create_customer()

        Create a new customer in API.

        parameters:
            customer_ref(string): A unique reference number for the
                    customer set by the client.
            email(string): A contact email address for the new customer
            first_name(string): The first name of the new customer
            surname(string): The surname of the new customer
            post_code(string): The postal code of the new customer
            line1(string): The first line of the customers postal address
            line2(string): The second line of the customers postal address
            account_number(string): The payment bank account number for
                    the new customer
            sort_code(string): The payment sort code for the new customer
            account_name(string): The customers name as it appears on
                    the bank account
        **parameters
            date_of_birth(datetime): The customers date of birth
            company_name(string): The company the customer represents
            home_phone(string): The customers home telephone number
            mobile_phone(string): The customers mobile telephone number
            work_phone(string): The customers work telephone number
            line3(string): The third line of the customers postal address
            line4(string): The fourth line of the customers postal address
            initials(string): The customers initials

        usage:
            It is possible to create a new customer using only the
            required parameters. It is also possible to use any number
            of the non-required parameters when creating a customer.
            Creating a customer using only the required parameters works
            like so

                create_customer('NEW-001', '[email protected]', 'Mr',
                'First', 'Test', 'GL514AA', 'Test road', '14785236', 
                '698741', 'Mr First Test')

            Creating a customer using the optional parameters works like so

                create_customer('NEW-002', '[email protected]', 'Mrs',
                'Second', 'Test', 'GL514AA', 'Test road', '36985214', 
                '784512', 'Mrs Second Test', company_name='Test company', 
                date_of_birth='1990-01-01')
    """

    arguments = self.customer_arguments

    parameters = {'customerRef': customer_ref,
                  'email': email,
                  'fistName': first_name,
                  'surname': surname,
                  'postCode': post_code,
                  'line1': line1,
                  'accountNumber': account_number,
                  'bankSortCode': sort_code,
                  'accountHolderName': account_name}

    existing_cref_error = 'There is an existing Customer with the same ' \
                          'Client and Customer ref in the database ' \
                          'already.'

    object_not_set_error = 'Object reference not set to an instance of ' \
                           'an object.'

    invalid_email_address_error = 'The provided Email is not a valid ' \
                                  'Email address.'

    post_code_empty = 'Post code cannot be empty.'

    invalid_post_code = 'Invalid Postcode. The postcode must have 5, ' \
                        '6 or 7 characters only'

    account_number_invalid = 'AccountNumber can only be 8 characters ' \
                             'long and only numbers.'

    sort_code_invalid = 'BankSortCode can only be 6 characters long  ' \
                        'and only numbers'

    sort_code_empty = 'Secure bank sort code cannot be empty.'

    line_1_empty = 'Address Line 1 cannot be empty'

    try:
        for key, value in keyword_arguments.items():
            if key in arguments:
                parameters.update({arguments[key]: value})
            else:
                raise InvalidSearchTerm

        header = self.header
        request_url = self.base_url + 'customer'

        request = self.session.post(request_url, headers=header,
                                    params=parameters)

        print(request.content)

        try:
            if request.json()['Detail'] == existing_cref_error:
                raise ExistingCustomer
            elif request.json()['Detail'] == object_not_set_error:
                raise MissingParameter
            elif request.json()['Detail'] == invalid_email_address_error:
                raise InvalidParameter
            elif request.json()['Detail'] == post_code_empty:
                raise InvalidParameter
            elif request.json()['Detail'] == invalid_post_code:
                raise InvalidParameter
            elif request.json()['Detail'] == account_number_invalid:
                raise InvalidParameter
            elif request.json()['Detail'] == sort_code_invalid:
                raise InvalidParameter
            elif request.json()['Detail'] == line_1_empty:
                raise InvalidParameter
            elif request.json()['Detail'] == sort_code_empty:
                raise InvalidParameter
            else:
                pass
        # Detail will not be present if an error is not generated.
        except TypeError:
            pass
        except KeyError:
            pass

    except InvalidSearchTerm:
        print(key + ' is not a valid argument. Make sure to check the '
                    'spelling. You can also refer to the docstring by '
                    'calling help(create_customer) for more assistance.')

    except MissingParameter:
        print('It looks like one or more of the required parameters is '
              'not present. Please double check this, and if needed, '
              'refer to the documentation.')

    except ExistingCustomer:
        print('The reference (' + customer_ref + ') is not unique.Please '
              'double check the reference. You are also able to '
              'cross-reference this by using query_customers()')

    except InvalidParameter:
        print('At least one of the parameters you have entered are '
              'invalid. Error details: ' + request.json()['Detail'])
\$\endgroup\$
1
  • 1
    \$\begingroup\$ Most of it looks good, some oddities here and there. What is your problem description? As in, it's an API wrapper of sorts, but why is it required and are there any particular requirements for it that your code happens to cover adequately that make it easier to use than the original non-wrapped version? \$\endgroup\$ Commented Jan 21, 2019 at 12:57

1 Answer 1

2
\$\begingroup\$

Some Python notes, else i have some difficulty wrapping my head around how the API is used.

String Formatting

Sometimes, string formatting simplifies things.

this

self.base_url = 'https://%s.apiprovider.co.uk/api/v3/client/%s/' %\
                        (environment, client_code)

can be made more readable:

self.base_url = 'https://{}.apiprovider.co.uk/api/v3/client/{}/'.format(
                                                              environment, client_code)

this too can be formatted:

print('The reference (' + customer_ref + ') is not unique.Please '
              'double check the reference. You are also able to '
              'cross-reference this by using query_customers()')

so that you don't have to worry about ++ each time

print('The reference ({}) is not unique.Please '
              'double check the reference. You are also able to '
              'cross-reference this by using query_customers()'.format(customer_ref))

and in py3.6+

print(f'The reference ({customer_ref}) is not unique.Please '
              'double check the reference. You are also able to '
              'cross-reference this by using query_customers()')

Adding Strings Together

For concatenating strings, adding () simplifies lots of \s

From this:

existing_cref_error = 'There is an existing Customer with the same ' \
                          'Client and Customer ref in the database ' \
                          'already.'

to this:

existing_cref_error = ('There is an existing Customer with the same '
                        'Client and Customer ref in the database '
                        'already.')
\$\endgroup\$
1
  • 1
    \$\begingroup\$ Thanks for taking the time to answer this after it went unseen for months. I've already began implementing a lot of what you've suggested, though it's definitely great advice to avoid code smells. \$\endgroup\$ Commented Aug 14, 2019 at 14:32

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.