不抽象:Increase API 设计原则

原文:Increase - 2024.04.26
(注:Increase 是一家提供金融技术服务的公司。)
API 资源是 API 的实体或对象。决定如何为这些实体命名和建模可以说是设计 API 最难也是最重要的部分。您所公开的资源组织了用户对您的产品如何工作以及它能做什么的心智模型。在 Increase,我们的团队采用了一项名为“不抽象”的原则来帮助我们。那么,这个原则是什么呢?
我们团队的大部分成员都来自 Stripe,在设计 API 时,我们考虑了在 Stripe 取得成功的相同价值观。Stripe 擅长在他们的 API 中进行抽象设计 —— 将复杂领域的基本特征提取出来,使用户能够轻松理解和操作。在他们的案例中,最显著的是将许多不同网络的支付建模到一个名为 PaymentIntent 的 API 资源中。例如,Visa 和 Mastercard 在发起退款的原因代码上存在细微差别,但 Stripe 将这些代码合并到一个枚举中,这样用户就不必分别考虑这两个支付网络。
这样做是有道理的,因为 Stripe 的许多用户都是早期创业公司,开发的产品与支付完全无关。他们不一定了解或需要了解信用卡的细微差别。他们希望快速集成 Stripe,继续开发自己的产品,而不再考虑支付问题。
“对 Increase 的用户来说,试图隐藏这些网络底层的复杂性会让他们感到烦恼,而不是简化他们的生活。”
Increase 的用户并非如此。他们通常对支付网络有深入的了解,一直在思考金融技术问题,之所以选择我们,是因为我们有直接的网络连接和深度集成,可以帮助他们构建支付网络。他们希望确切知道 FedACH 窗口何时关闭,转账何时到账。他们知道,在 ACH 转账上设置不同的 Standard Entry Class code 会导致不同的返回时间。试图隐藏这些网络的潜在复杂性(例如,通过单一 API 资源对 ACH 转账和电汇进行建模)会让他们感到烦恼,而不是简化他们的生活。
(注:ACH 是美国主要使用的电子支付系统。FedACH 则是美联储提供的 ACH 服务。)
与这些用户的早期对话帮助我们在构建第一版 API 时明确了“不抽象”原则。下面举例说明这种思维方式对 API 设计的影响:
现实的(Real-world)命名
我们倾向于使用底层网络的词汇,而不是自己为 API 资源及其属性命名。例如,在通过 Increase API 进行 ACH 转账时,我们公开的参数就是以 Nacha 规范中的字段命名的。
(注:Nacha 规范用于指导金融机构如何正确、安全地使用 ACH 网络进行电子交易。)
不可变性
与使用网络术语的方式类似,我们也尝试根据现实世界中的事件(如采取的行动或发送的消息)来为我们的资源建模。这使得我们更多的 API 资源是不可变的。对这种 API 来说,一种行之有效的方法是将这些不可变资源(例如,作为 ACH 转账生命周期的一部分可以发送的所有网络消息)集中起来,并将它们归类到一个状态机“生命周期对象”中。例如,我们 API 中的 ach_transfer 对象有一个名为 status 的字段,它会随着时间的推移而变化,还有几个不可变的子对象,会随着转账在其生命周期中的移动而被创建。一个新创建的 ach_transfer 对象看起来像这样:
{"id": "ach_transfer_abc123","created_at": "2024-04-24T00:00:00+00:00","amount": 1000,"status": "pending_approval","approval": null,"submission": null,"acknowledgement": null// 为了清晰起见,这里省略了其他字段
}
在同一笔转账通过我们的管道并提交给 FedACH 后,它看起来像这样:
{"id": "ach_transfer_abc123","created_at": "2024-04-24T00:00:00+00:00","amount": 1000,"status": "submitted",// 不可变的,当转账被批准时填充"approval": {"approved_by": "administrator@yourcompany.com","approved_at": "2024-04-24T01:00:00+00:00"},// 不可变的,当转账被提交时填充"submission": {"trace_number": "058349238292834","submitted_at": "2024-04-24T02:00:00+00:00"},// 不可变的,当转账被确认时填充"acknowledgement": {"acknowledged_at": "2024-04-24T03:00:00+00:00"}// 为了清晰起见,这里省略了其他字段
}
按用例分离资源
对于给定的 API 资源,如果用户可以在该资源的不同实例上执行的操作集差异很大,我们倾向于将其拆分为多个资源。例如,您可以对发起的 ACH 转账执行的操作集与接收的 ACH 转账执行的操作集不同(实际上完全相反),因此我们将其分为 ach_transfer 和 inbound_ach_transfer 资源。
这种方法可能会使我们的 API 更为冗长,乍看之下令人生畏–我们的文档页面左侧有很多资源!不过,我们认为从长远来看,这种方法更具有前瞻性和可预测性。
重要的是,我们的工程团队已经承诺采用这种方法。设计一个复杂的 API 需要数年的时间,这期间会不断做出小的增量决策。预先承诺“不抽象”原则减轻了这些决策的认知负担。例如,在向美联储发送电汇时,有一个名为Input Message Accountability Data 的必填字段,它是该电汇的全球唯一 ID。在构建支持电汇的功能时,API 抽象程度高的的工程师可能需要深思熟虑如何以“用户友好”的方式命名这个字段–trace_number、reference_number、id…等等。在 Increase,这位假设的工程师会将字段命名为 input_message_accountability_data,然后继续工作。当 Increase 的用户第一次遇到这个字段时,虽然一开始可能不是最容易识别的名称,但这可以帮助他们立即了解这个字段是如何映射到底层系统的。
“不抽象”原则并不适合每个 API,但考虑适合开发人员集成 API 的抽象程度是一项有价值的工作。这将取决于开发人员在您的产品领域的工作经验水平,以及他们为集成所投入的精力等。如果您正在构建一个抽象程度高的 API,那么在添加新功能之前,请深思熟虑。如果您要构建的是抽象程度低的 API,则应致力于此,并抵制在出现新功能时添加抽象功能的诱惑。
相关文章:
不抽象:Increase API 设计原则
原文:Increase - 2024.04.26 (注:Increase 是一家提供金融技术服务的公司。) API 资源是 API 的实体或对象。决定如何为这些实体命名和建模可以说是设计 API 最难也是最重要的部分。您所公开的资源组织了用户对您的产品如何工作…...
mybatis调用数据库存储过程
mybatis调用数据库存储过程及常见属性详解 调用mapper String visitCode mapper.getVisitCode(objectMap);Dao层,xml文件代码编写 <select id"getVisitCode" parameterType"map" resultType"string" statementType"CALLAB…...
【git】发生冲突后回滚提交
gerrit 冲突, 无法合并到主干 那么先回滚 参考这里的 reset 操作: 回滚 到上一个提交 $ git reset --soft HEAD~1 # 數字表示移動到 HEAD後面第幾個刚提交的会撤回, stash 刚刚提交的 然后去pull 最新的 修改冲突: 最后再…...
ISO14229 -1 UDS诊断服务记录-001:0x34\0x36\0x37\0x31\0x19\0x14服务报文格式介绍
目录 1、34服务-请求下载 1.1、诊断请求格式 1.2、正响应格式 1.3、负响应格式 1.4、工程应用分析 2、36服务-传输数据 2.1、请求报文格式 2.2、正响应格式 2.3、负响应NRC 3、37服务-退出传输 3.1、报文格式 3.2、正响应格式 3.3、负响应NRC 4、31服务-例程控制 …...
使用 MediaMTX 和 FFmpeg 推拉 RTSP 流媒体
实时流传输协议 RTSP(Real-Time Streaming Protocol)是 TCP/IP 协议体系中的一个应用层协议,由哥伦比亚大学、网景和 RealNetworks 公司提交的 IETF RFC 标准。该协议定义了一对多应用程序如何有效地通过 IP 网络传送多媒体数据。RTSP 在体系…...
Mac 电脑安装 Raptor 流程图软件的方法
0. 安装逻辑 (1)运行 raptor,本质上需要 mac 能够运行 windows 程序,因此需要安装 .NET Runtime 7.0,这是微软程序运行必须的文件。 (2)运行 raptor 还需要安装依赖文件 mono-libgdiplus。 &am…...
W801学习笔记二十:宋词学习应用
前三章完成了唐诗的应用,本章将实现宋词的学习应用。 宋词与唐诗的区别不大,马上开始。 1、我们需要参考前面唐诗的方式,把宋词文本下载下来,并进行格式整理。 W801学习笔记十七:古诗学习应用——上 2、在菜单中添加…...
EPAI手绘建模APP转换模型和坐标系
(11) 模型转换 图 273 转换工具栏 ① 实体转成曲面,先选择需要转成曲面的实体模型,再点击该按钮。将选择的实体模型转成多个曲面。 ② 曲线转成NURBS样条曲线,先选择需要转成NURBS样条曲线的边模型,修改转换参数,将选…...
STM32快速入门(串口传输之USART)
STM32快速入门(串口传输之USART) 前言 USART串口传输能实现信息在设备之间的点对点传输,支持单工、半双工、全全双工,一般是有三个引脚:TX、RX、SW_RX(共地)。不需要一根线来同步时钟。最大优…...
什么是网络安全和网络隐私?
什么是网络安全?这个是我最感兴趣的话题,网络安全说白了就是在网络上的安全,跟现实中一样,现实中为了家里的安全,我们会给家门上锁,会装监控,农村的话可能还会养一条狗,只有我们让别人进我们家,别人才能进来,对于计算机来说也是一样的,我们会设置账户的密码,会设置防火墙,会安…...
树莓派变小路由器放出热点wifi
环境 树莓派4Bubuntu20 作用 树莓派放出wifi后,笔记本电脑连接树莓派的wifi,并且ip配置在一个网段,就可以互相通信(笔记本放出wifi,树莓派连接效果一样),这样的好处是树莓派只要一上电就会自…...
数据猎手:使用Java和Apache HttpComponents库下载Facebook图像
引言 在信息驱动的时代,互联网上的数据成为了无可比拟的宝藏。本文旨在探讨如何通过利用Java和Apache HttpComponents库,从全球最大的社交网络平台Facebook上获取图像数据。 作为全球最大的社交网络平台,Facebook聚集了数以亿计的用户&#…...
uniapp——阻止冒泡
点击事件阻止冒泡 click.stop"onSubmit"其他类型,比如视频: 最后加了一个 click.stop <view class"videoBox" v-if"item.video_url"><video :src"i.image(item.video_url)" :controls"true&quo…...
Jmeter性能测试(四)
一、遇到问题解决思路 1、检查请求头是否正确 2、检查请求参数是否正确 3、检查鉴权信息是否正确 4、检查变量作用域 5、检查数据提取是否正确(正则/json提取器) 二、请求头检查 1、在Http信息头管理器查看 2、注意这里的变量作用域是全局的 三、请求参数检查 1、在查看结…...
从零开始精通RTSP之传输ADPCM等音频流
概述 在上一篇文章中,我们详细介绍了使用RTP传输AAC音频流的打包方法。除了AAC编码算法外,常用的音频编码算法还有ADPCM、G711A、G711U、G726等。接下来,我们继续介绍RTP传输ADPCM等音频流的打包方法。 封装方法 RTP封装ADPCM等音频数据时&am…...
box-decoration-break 使用介绍
box-decoration-break属性的使用 一、定义 box-decoration-break是CSS片段模块(CSS Fragmentation Module Level 3)中的一个属性,主要用于指定背景(background)、内边距(padding)、边框&#…...
技术分享 | 京东商品API接口|京东零售数据可视化平台产品实践与思考
导读 本次分享题目为京东零售数据可视化平台产品实践与思考。 主要包括以下四个部分: 1.京东API接口介绍 2. 平台产品能力介绍 3. 业务赋能案例分享 01 京东API接口介绍 02 平台产品能力介绍 1. 产品矩阵 数据可视化产品是一种利用数据分析和可视化技术&…...
OpenHarmony鸿蒙蓝牙BLE调试app
OpenHarmony蓝牙模块提供了ble的功能,本篇提供一个简单的app供测试时使用。代码使用API10,对应4.0Release版本固件。 1.开启BLE 开启BLE前,先在设置界面中打开蓝牙开关。 openBle()函数负责打开ble扫描,并打印扫描结果。主要代…...
HackMyVM-VivifyTech
目录 信息收集 arp nmap nikto whatweb WEB web信息收集 wpscan feroxbuster hydra 提权 系统信息收集 横向渗透 git提权 get root 信息收集 arp ┌──(root㉿0x00)-[~/HackMyVM] └─# arp-scan -l Interface: eth0, type: EN10MB, MAC: 08:00:27:9d:6d:7b, …...
将unity中相机位置保存为json 文件或者 发送给后端
将unity中相机位置保存保存到服务器 ///相机的位置public Transform cameraTransform;void Start(){// SaveCameraPosition("sd");// ("{\"name\":\"sd\",\"position\":\"(0.00, 5.00, -12.00)\",\"rotation\&qu…...
python打卡day49
知识点回顾: 通道注意力模块复习空间注意力模块CBAM的定义 作业:尝试对今天的模型检查参数数目,并用tensorboard查看训练过程 import torch import torch.nn as nn# 定义通道注意力 class ChannelAttention(nn.Module):def __init__(self,…...
Admin.Net中的消息通信SignalR解释
定义集线器接口 IOnlineUserHub public interface IOnlineUserHub {/// 在线用户列表Task OnlineUserList(OnlineUserList context);/// 强制下线Task ForceOffline(object context);/// 发布站内消息Task PublicNotice(SysNotice context);/// 接收消息Task ReceiveMessage(…...
【入坑系列】TiDB 强制索引在不同库下不生效问题
文章目录 背景SQL 优化情况线上SQL运行情况分析怀疑1:执行计划绑定问题?尝试:SHOW WARNINGS 查看警告探索 TiDB 的 USE_INDEX 写法Hint 不生效问题排查解决参考背景 项目中使用 TiDB 数据库,并对 SQL 进行优化了,添加了强制索引。 UAT 环境已经生效,但 PROD 环境强制索…...
前端开发面试题总结-JavaScript篇(一)
文章目录 JavaScript高频问答一、作用域与闭包1.什么是闭包(Closure)?闭包有什么应用场景和潜在问题?2.解释 JavaScript 的作用域链(Scope Chain) 二、原型与继承3.原型链是什么?如何实现继承&a…...
OpenLayers 分屏对比(地图联动)
注:当前使用的是 ol 5.3.0 版本,天地图使用的key请到天地图官网申请,并替换为自己的key 地图分屏对比在WebGIS开发中是很常见的功能,和卷帘图层不一样的是,分屏对比是在各个地图中添加相同或者不同的图层进行对比查看。…...
算法:模拟
1.替换所有的问号 1576. 替换所有的问号 - 力扣(LeetCode) 遍历字符串:通过外层循环逐一检查每个字符。遇到 ? 时处理: 内层循环遍历小写字母(a 到 z)。对每个字母检查是否满足: 与…...
在鸿蒙HarmonyOS 5中使用DevEco Studio实现企业微信功能
1. 开发环境准备 安装DevEco Studio 3.1: 从华为开发者官网下载最新版DevEco Studio安装HarmonyOS 5.0 SDK 项目配置: // module.json5 {"module": {"requestPermissions": [{"name": "ohos.permis…...
通过 Ansible 在 Windows 2022 上安装 IIS Web 服务器
拓扑结构 这是一个用于通过 Ansible 部署 IIS Web 服务器的实验室拓扑。 前提条件: 在被管理的节点上安装WinRm 准备一张自签名的证书 开放防火墙入站tcp 5985 5986端口 准备自签名证书 PS C:\Users\azureuser> $cert New-SelfSignedCertificate -DnsName &…...
Ubuntu系统复制(U盘-电脑硬盘)
所需环境 电脑自带硬盘:1块 (1T) U盘1:Ubuntu系统引导盘(用于“U盘2”复制到“电脑自带硬盘”) U盘2:Ubuntu系统盘(1T,用于被复制) !!!建议“电脑…...
HTML前端开发:JavaScript 获取元素方法详解
作为前端开发者,高效获取 DOM 元素是必备技能。以下是 JS 中核心的获取元素方法,分为两大系列: 一、getElementBy... 系列 传统方法,直接通过 DOM 接口访问,返回动态集合(元素变化会实时更新)。…...
