SDK writing idea of calling mobile phone charge recharge API

Time:2021-10-15

thinking

By dividing the data returned in the SDK method into two parts: normal return data and error return data, the caller can handle the interface call error more easily.
The process of SDK calling the third-party service interface is divided into three parts: data preparation, HTTP request and result processing to reuse the code.

example

Take the compilation of aggregated data mobile phone charging SDK as an example,Official document of mobile phone charging API

# encoding=utf-8
from urlparse import urljoin
from hashlib import md5
from datetime import datetime
from random import sample
import requests
import pytz


class APIError(object):
    def __init__(self, code, msg):
        self.code = code
        self.message = msg


class JuhePhoneChargeApi(object):

    API_PREFIX = 'https://op.juhe.cn/ofpay/mobile/'
    def __init__(self, openid, key, api_entry=None):
        self._key = key
        self._openid = openid
        self._api_entry = api_entry or self.API_PREFIX


    def telcheck(self, phoneno, cardnum):
        params = {'phoneno': phoneno, 'cardnum': cardnum}
        return self._get(path='telcheck', params=params)

    def telquery(self, phoneno, cardnum):
        params = {
            'phoneno': phoneno,
            'cardnum': cardnum,
        }
        return self._get(path='telquery', params=params)

    def onlineorder(self, phoneno, cardnum, orderid):
        params = {
            'phoneno': phoneno,
            'cardnum': cardnum,
            'orderid': orderid or self.create_orderid(),
        }
        params.update({'sign': self._create_sign(**params)})

        return self._get(path='onlineorder', params=params)

    def ordersta(self, orderid):
        params = {'orderid': orderid}
        return self._get(path='orderid', params=params)

    def create_orderid(self):
        return ''.join((
            datetime.now(tz=pytz.timezone('Asia/Shanghai')).strftime('%Y%m%d%H%M%S%f'),
            self._create_code(12)))

    def _process_response(self, rsp):
        """
        Do the same processing for the data returned by the third-party interface,
        :param rsp:
        : Return: normal return value of the interface, wrong object
        """
        if rsp.status_code != 200:
            return None, APIError(rsp.status_code, 'http error')
        try:
            content = rsp.json()
        except:
            return None, APIError(99999, 'invalid rsp')
        if 'error_code' in content and content['error_code'] != 0:
            return None, APIError(content['error_code'], content['reason'])

        return content['result'], None


    def _get(self, path, params=None):
        if not params:
            params = {}

        headers = {'Content-type': 'application/json'}
        params.update({'key': self._key})

        rsp = requests.get(urljoin(self._api_entry, path), params=params, headers=headers)
        return self._process_response(rsp)


    def _create_sign(self, phoneno, cardnum, orderid=None):
        obj_str = ''.join((
            self._openid, 
            self._key, 
            phoneno, 
            str(cardnum), 
            orderid or self.create_orderid()))

        m = md5()
        m.update(obj_str)
        return m.hexdigest()

    def _create_code(self, number_len):
        ELEMENT = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
        return ''.join(sample(ELEMENT, number_len))