不抽象: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…...
应用升级/灾备测试时使用guarantee 闪回点迅速回退
1.场景 应用要升级,当升级失败时,数据库回退到升级前. 要测试系统,测试完成后,数据库要回退到测试前。 相对于RMAN恢复需要很长时间, 数据库闪回只需要几分钟。 2.技术实现 数据库设置 2个db_recovery参数 创建guarantee闪回点,不需要开启数据库闪回。…...
如何在看板中有效管理突发紧急任务
在看板中有效管理突发紧急任务需要:设立专门的紧急任务通道、重新调整任务优先级、保持适度的WIP(Work-in-Progress)弹性、优化任务处理流程、提高团队应对突发情况的敏捷性。其中,设立专门的紧急任务通道尤为重要,这能…...
Qt Http Server模块功能及架构
Qt Http Server 是 Qt 6.0 中引入的一个新模块,它提供了一个轻量级的 HTTP 服务器实现,主要用于构建基于 HTTP 的应用程序和服务。 功能介绍: 主要功能 HTTP服务器功能: 支持 HTTP/1.1 协议 简单的请求/响应处理模型 支持 GET…...
C#中的CLR属性、依赖属性与附加属性
CLR属性的主要特征 封装性: 隐藏字段的实现细节 提供对字段的受控访问 访问控制: 可单独设置get/set访问器的可见性 可创建只读或只写属性 计算属性: 可以在getter中执行计算逻辑 不需要直接对应一个字段 验证逻辑: 可以…...
Modbus RTU与Modbus TCP详解指南
目录 1. Modbus协议基础 1.1 什么是Modbus? 1.2 Modbus协议历史 1.3 Modbus协议族 1.4 Modbus通信模型 🎭 主从架构 🔄 请求响应模式 2. Modbus RTU详解 2.1 RTU是什么? 2.2 RTU物理层 🔌 连接方式 ⚡ 通信参数 2.3 RTU数据帧格式 📦 帧结构详解 🔍…...
0x-3-Oracle 23 ai-sqlcl 25.1 集成安装-配置和优化
是不是受够了安装了oracle database之后sqlplus的简陋,无法删除无法上下翻页的苦恼。 可以安装readline和rlwrap插件的话,配置.bahs_profile后也能解决上下翻页这些,但是很多生产环境无法安装rpm包。 oracle提供了sqlcl免费许可,…...
6个月Python学习计划 Day 16 - 面向对象编程(OOP)基础
第三周 Day 3 🎯 今日目标 理解类(class)和对象(object)的关系学会定义类的属性、方法和构造函数(init)掌握对象的创建与使用初识封装、继承和多态的基本概念(预告) &a…...
智警杯备赛--excel模块
数据透视与图表制作 创建步骤 创建 1.在Excel的插入或者数据标签页下找到数据透视表的按钮 2.将数据放进“请选择单元格区域“中,点击确定 这是最终结果,但是由于环境启不了,这里用的是自己的excel,真实的环境中的excel根据实训…...
rk3506上移植lvgl应用
本文档介绍如何在开发板上运行以及移植LVGL。 1. 移植准备 硬件环境:开发板及其配套屏幕 开发板镜像 主机环境:Ubuntu 22.04.5 2. LVGL启动 出厂系统默认配置了 LVGL,并且上电之后默认会启动 一个LVGL应用 。 LVGL 的启动脚本为/etc/init.d/pre_init/S00-lv_demo,…...
智能照明系统:具备认知能力的“光神经网络”
智能照明系统是物联网技术与传统照明深度融合的产物,其本质是通过感知环境、解析需求、自主决策的闭环控制,重构光与人、空间、环境的关系。这一系统由智能光源、多维传感器、边缘计算单元及云端管理平台构成,形成具备认知能力的“光神经网络…...
