python - 这是 Pythonic API 设计策略吗?

标签 python api authorize.net payment-processing

这是我要问的问题的前奏:我已经开始用 Python 为我的公司构建一个与网关无关的支付 API。目前,我只编写了支持 Authorize.net 的代码,并希望比我更有经验的 Python 程序员对我的 API 设计的清晰度提供一些反馈。

我选择自己推出,因为现有的其他包感觉更像是事后的想法,或者是特定于 Authorize.net 的(我想编写一个界面更简洁的更通用的包)。我特别从一个包 ( pythorize ) 中获得了一些灵感,但不喜欢他们的 API。

在我开始描述我在做什么之前,这里是包的 bitbucket 上公共(public)存储库的链接:paypy (注意那些可能想要使用它的人:代码是稳定的,但文档严重缺乏)。

我目前的策略是使用嵌套字典并将其传递给支付方法类的构造函数。在 Authorize.net CIM API 上创建新用户配置文件的示例:

>>> options = {'tran_key' : 'test_tran_key',
...            'login'    : 'developer_login',
...            'testing'  : True,
...            'validation': 'testMode',
...            'customer': {'description': 'Some description of the customer profile', 
...                         'id'         : 22,
...                         'email'      : 'johnny_doe@gmail.com'},
...            'billing': [{'type': 'individual',
...                         'profile': {'city'      : 'Carlsbad',
...                                     'state'     : 'California',
...                                     'zip'       : '92009',
...                                     'firstname' : 'John',
...                                     'address'   : '12 Alicante Rd. Suite 9',
...                                     'lastname'  : 'Doe',
...                                     'country'   : 'USA',
...                                     'phone'     : '(858) 557-2674'},
...                         'payment': {'card': {'ccv'        : '524',
...                                              'number'     : '4111111111111111',
...                                              'expiration' : '2014-04'}}},
...                        {'type'    : 'individual',
...                         'profile' : {'city'      : 'Las Vegas',
...                                      'state'     : 'Nevada',
...                                      'zip'       : '79112',
...                                      'firstname' : 'John',
...                                      'address'   : '78 Cloud Front',
...                                      'lastname'  : 'Doe',
...                                      'country'   : 'USA',
...                                      'phone'     : '(858) 557-2674'},
...                         'payment': {'card': {'ccv'        : '499',
...                                              'number'     : '4111111111111111',
...                                              'expiration' : '2012-11'}}},
...                        {'profile': {'city'       : 'Carlsbad',
...                                     'state'      : 'California',
...                                     'zip'        : '92009',
...                                     'firstname'  : 'John',
...                                     'address'    : '12 Alicante Rd. Suite 9',
...                                     'lastname'   : 'Doe',
...                                     'company'    : 'Xmarks',
...                                     'country'    : 'USA',
...                                     'phone'      : '(858) 557-2674'},
...                         'payment': {'bank': {'name_on_account' : 'John Doe',
...                                              'account'         : '829330184383',
...                                              'type'            : 'checking',
...                                              'name'            : 'Bank of America',
...                                              'routing'         : '122400724'}}}],
...            'shipping': [{'city'       : 'Carlsbad',
...                          'state'      : 'California',
...                          'zip'        : '92009',
...                          'firstname'  : 'John',
...                          'address'    : '12 Alicante Rd. Suite 9',
...                          'lastname'   : 'Doe',
...                          'country'    : 'USA',
...                          'phone'      : '(858) 557-2674'}]}
>>> profile = Profile(options)
>>> result  = profile.create()
>>> result.code
'I00001'
>>> print 'Customer Profile ID:' + str(result)
Customer Profile ID: 2758851
>>> print 'Customer Payment Profile IDs:' + repr(result.payment_ids)
Customer Payment Profile IDs: ['2380878', '2380879', '2380880']
>>> print 'Customer Shipping Profile IDs:' + repr(result.shipping_ids)
Customer Shipping Profile IDs: ['2427568']
>>>
>>>
>>> options = {'id'        : str(result),
...            'tran_key' : '86U5pvA9TcxZ5b8D',
...            'testing'  : True,
...            'login'    : '5b3PhGX68'}
>>> profile = Profile(options)
>>> result  = profile.remove()
>>> result.code
'I00001'
>>> ^D

您会注意到我对结果对象使用了几个神奇的方法(如 str 等...)。我也将字典策略用于 AIM 和 ARB 方法,并认为这是向支付 API 传达“选项”的最简单方法——因为在某些时候会有适用于 GoogleCheckout、Paypal 等的适配器...

我的另一个想法是使用描述符和对象而不是字典来将选项数据传送给适配器。

与所有支付网关 API(特别是 PayPal 和 Authorize.net 的)一样,接口(interface)往往有点困惑并且没有以任何方式标准化,因此很难避免一些依赖于网关的选项。

最佳答案

深度嵌套的字典在 Python 中可能并不罕见,也许它们是“Pythonic”,但它确实不是一个好主意,所以我会声称它不是 Pythonic。

我会创建一个嵌套的类层次结构。 IMO,这样会更清楚,并且还可以让您进行类型检查。

事实上,我可能会使用一些模式模块来做到这一点。

您应该如何输入该数据?人们不应该输入 Python 代码,对吧?

关于python - 这是 Pythonic API 设计策略吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4380749/

相关文章:

python - 使用 bluez python dbus 接口(interface)连接到蓝牙 LE 设备

python - 对 Python 函数的代码(包括 lambda)进行哈希处理

javascript - HERE Api Map 只显示实际 map 的一小部分,不具有交互性

api - 并发环境中的幂等 PUT

python - 请求 JSON 格式不正确

testing - authorize.net 测试在测试模式下下降

python - 在单元测试中模拟对象时避免输入类型警告?

Python : How to find in set of rows, 一个元素小于1而其他元素大于1?

python - 如何迭代地将 lxml.objectify.ObjectifiedElement 从authorize.net 转换为 python 字典

php - Authorize.net CIM - 无效/退款交易