Java API设计实战指南:打造稳健、用户友好的API
实践案例:通过API优化加快上市时间
案例背景
作者曾为一家初创公司的新产品打造MVP(最小可行性产品)。MVP的想法非常简单:需要使用单页应用(SPA)框架构建一个小型用户界面,以及一个公开REST API的WEB服务,API主要用于与SPA和战略业务合作伙伴集成。
但作者在项目实际启动后,遇到了一些严重的问题:
1. 缺乏完整的API文档和规范:
· API文档不完整、错误百出,无法作为准确的参考。
· 没有约定的API测试流程,导致后端开发团队可以在未经通知的情况下随意更改和发布API。这种变动经常是bug,并且破坏了与API客户端的集成。
2. 不恰当的API框架和验证:
· 后端团队使用了不适当的Flask框架,并自行实现了复杂的有效负载验证,其中大部分没有经过测试。
· 验证部分代码数量庞大,包括日期、时间戳和字符串格式验证,但没有经过充分测试,这严重拖慢了项目进度。
因此,解决上述问题就需要修复和完善API文档,确保其准确性和完整性;建立适当的API框架,以提高代码质量和可测试性;设立严格的API规范,防止不符合规范的版本发布。
修复API设计和文档
从上面暴露出来的问题可以看出,该开发团队对REST API的最佳实践和OpenAPI规范并不了解。因此,开发团队需要先理解OpenAPI及其工作原理,将API文档整合到OpenAPI规范中,从而更清晰地理解API的预期行为。
在将文档整合到OpenAPI规范的过程中,我们发现了许多先前API设计中的问题。例如,以前采用的自定义日期格式需要在服务器和UI中使用自定义验证逻辑。我们转而采用OpenAPI支持的ISO标准来表示日期,解决了这个问题。
另外,一些模式过于灵活,导致验证几乎失效。为了改进验证,我们重构了这些模式,并为每个实体创建了一个具有不同端点的模型,使其更具可用性。
之前设计中不适当地使用了HTTP方法和状态码。团队只使用GET和POST方法,所有响应都返回200状态码。这种不当的使用使得在尝试创建、删除或更新资源时变得不清晰。为了解决这个问题,我们重新定义了HTTP方法的使用,并正确返回适当的状态码,以便更准确地表明请求的成功或失败。
此前设计的另一个限制是“端点重用”。虽然看似节省代码,但实际上它公开了太多实现细节。所以要强调先设计API,再考虑实现的理念。
将API规范与OpenAPI合并是项目的一个重要转折点。此后,我们能够在与后端集成之前运行模拟服务器来构建和测试UI,也能够根据规范验证后端实现。我们采用Prism运行模拟服务器,并使用Dredd验证服务器实现(虽然我现在更倾向于使用Schemathesis)。这使得项目能更清晰、更高效地发展。
修复API的发布过程
即便有了API文档,但在发布前没有针对API规范跑通测试,文档的作用也会变得有限。尽管文档本身能帮助我们理解API的运作方式,但其真正强大之处在于它作为验证工具的功能——验证服务器的正确实现。
为确保API服务器按照预期运行,我将Dredd测试套件纳入了持续集成服务器中。除非通过了Dredd验证并符合API规范,否则没有人能够将新代码合并并发布,这一步让团队避免了对API服务器的不经意修改。从此,所有对服务器的更改都需事先记录,并确保API服务器在合并或发布前遵循这些更改。这种做法保证了服务器的稳定性和一致性。
选择适合的API开发框架
此前团队在API服务器上采用了Flask框架来实现,这是一种用于构建Web应用程序的流行Python框架。他们以基础的Flask构建API,并编写了大量自定义代码来验证API有效负载。这是许多经验不足的API开发人员常见的一个错误。
构建自定义API验证层并非不可取,但过度依赖此方法可能导致重复造轮子。API需要复杂的验证逻辑来处理有效负载和URL(路径与查询参数),这些逻辑必须贯穿整个API。因此,如果坚持自建API验证层,最终会产生一个API框架。然而,现有许多优秀的API开发框架可供选择,为何不选择其中之一呢?
特别是针对Flask,有多种选择可供考虑。但并非所有框架都一样。例如,flasgger、restx(flask-restplus的后继产品)、flask-RESTful和flask-smorest等。在这么多选择中,如何做出决策呢?
在选择REST API开发框架时,主要考虑以下因素:
· 支持OpenAPI:框架应允许轻松构建REST API并自动生成API文档,确保有效载荷验证的正确性。可参考框架有Flasgger和flask-smorest。
· 健壮的数据验证:验证有效载荷需要强大的数据验证库来处理各种属性和类型。库应支持可选和必需的属性,如字符串格式(ISO日期和UUID),以及严格和宽松的类型验证。在Python生态系统中,pydantic和marshmallow是优秀的数据验证库,Flasgger和flask-smorest可以使用marshmallow。
· 全面验证:框架应支持请求有效载荷、响应有效载荷、URL路径参数和URL查询参数的验证。某些库可能只验证请求有效负载,而忽略URL参数或响应有效负载。确保框架提供至少一种方式来强制执行验证规则。如果使用marshmallow,可直接使用其模型验证响应有效负载。
· 成熟度:选择成熟、稳定且拥有活跃社区支持的库。它应具备良好的文档和快速解决用户问题的能力。
根据以上因素评估后,选择flask-smorest这款Flask插件,支持使用marshmallow轻松构建REST API的数据验证。能够简化数据验证流程,减少了自定义代码量。现在,请求和响应有效载荷都得到了正确的验证,并且marshmallow也处理了URL查询和路径参数的验证。
选择合适的API框架让我们拥有了一个正常运作的API。由于框架能够处理API层的细节,我们能够更专注于业务逻辑和应用程序的数据模型,从而提高了开发速度并且能够更频繁地发布更加优质的软件。
综合考量以构建卓越API
在当下的互联网,API无处不在且无可避免。然而,真正构建良好的API却是一项复杂的任务,与编写可读性强且易于维护的代码一样,构建高质量、易用且易于修改的接口也是API开发中的挑战。
提供优质API是有难度的,因为它需要与业务需求保持一致,即客户端和服务器端必须使用相同的约定和规范,否则集成将难以实现。
实现这一目标需要考虑多个方面:收集客户需求,将需求转化为技术细节,设计API,编写文档,选择合适的API框架并正确使用它,测试API,并确保实现符合设计规范。这还不包括API的安全性、部署和操作等方面。
对于构建关键业务API,建议是不要让初级开发人员单独承担。他们可以参与,但需要高级开发人员来指导他们的工作。如果没有API开发经验,就遵循最佳实践路径:先设计API,再编写文档,按照规范进行实现,并对其进行验证。不要重新发明轮子,选择合适的框架!
尽管学习OpenAPI、了解API测试框架、研究API开发框架等可能需要付出一定时间成本,但这是值得的。如若不然,则会陷入API集成和软件质量问题的恶性循环,这将阻碍项目进展并造成巨额成本来修复问题。
如果本身资源充足且拥有经验丰富的API开发人员,正确构建API的概率大幅提升,且能节省下大量的资金。除此之外,还要重视API的管理,很多问题不仅在于前期的开发与支出成本,开发过程中隐藏的代码问题、负责员工的离职交接不清都可能造成隐患。因此幂简集成认为,API的管理可以借助第三方工具一站式管理API,多角色参与,避免责任推诿,还可以提升开发效率。