API 设计的最佳实践
优秀的API设计话题,在很多团队涌现,这些团队正在努力完善他们的API策略。
在之前发布的博客上,我简要的讨论了 API设计的重要性 。一个设计良好的API应该包含那些好处:你的API应该能提高开发者经验、方便的快捷文档和高可用性。
但优秀的API设计究竟应该怎么做?在这个博客中,我将详细的介绍一些RESTful API的最佳设计。
一个设计良好的API的特点
一般来说,一个有效的API设计遇有以下特点:
- 易于阅读和使用 。一个设计良好的API应该很容易被使用,其资源和相关操作能够快速的被使用它的开发人员记忆。
- 难以误用。 设计良好的API实现和集成将是个简单的过程,写出错误代码将变得不太可能。没有严格按照API开发指南的终端用户将会得到详实的信息反馈。
- 完整又简洁. 最后,一个完整的API应该具有成熟的应用防止你的数据被泄露。API完整性会随着时间的推移而改变,大多数的API设计人员和开发人员都应在现有基础上逐步构建新的API。这是每一个使用API的工程师或公司都必须坚持的理念。
为说明下面列出的概念, 我会以一个照片分享的应用程序举例。 该应用程序允许用户上传照片, 以拍摄地点和心情标签描述照片特征。
集合,资源及其网址
了解资源和集合
资源是REST概念的基础。 一条资源是一个重要对象,它本身可以被引用。 一条资源含有数据,与其他资源的关系,以及操作方法,以允许访问和处理相关信息。
一组资源被称为一个集合。 集合和资源的内容取决于你的组织和消费者的需求。 例如,如果你认为,市场获得了你的产品用户群的基本信息会受益, 那么,你就可以将此作为集合或资源。
统一资源定位器(URL)确定了资源的在线位置。 URL指向你API资源存在的位置。 基URL是这个位置的一致部分。
在照片分享应用一例中, 我们可以公开用户数据,只要用户通过集合和资源使用该应用程序, 经由适当的URL访问。
- /users :用户的集合。
- /users/username1 :一个特定用户的信息资源。
名词化的URL更好
URL应该是整洁、优雅和简单的,这样开发人员更易在他们的web程序中使用你的产品。 很长且难以理解的URL不仅看起来很糟糕,而且在记录时容易出现错误。所以使用名词应该是很好的。
没有规定让资源名词使用单数或复数,但是在如果是集合的话使用复数无疑很好的。 具有相似的资源和集合分别保持它们的一致性是较好的做法。
保持这些名词的自解释性,有助于开发人员了解从URL描述的资源, 这最终会使他们使用你的API。
回到照片分享应用程序,它拥有返回集合的公共API /users 、/photos。注意到它们都是复数名词了吗? 它们也是自描述的,我们可以推断出 /users 和/photos分别是获取产品注册的用户信息和分享的照片。
用HTTP方法来描述资源的功能
所有资源都有一组方法,可以对它们进行操作由该接口暴露的数据。
REStful APIs包含主要的HTTP方法,其良好的定义和独立的功能能够应对所有资源。这里是RESTful API里常用HTTP方法列表,这些方法定义CRUD如何操作资源和集合。
(如果你想了解PUT和PATCH的不同, 可以到StackOverflow上看看这个 .)
虽然在URL中使用动词也不错,但是GET, PUT, POST, DELETE操作已经用于描述了资源的操作,因此在URL中使用动词代替名词会显得比较混乱。
在照片分享app中,/users 和/photos 是一个端点,API的终端消费者可以更直观的使用RESTful CRUD 进行上述的操作。
响应
提供反馈,以帮助开发人员成功
在他们使用你的产品时向开发人员提供良好的反馈,对于提升使用率和用户维持率是很好的。每一个客户端的请求和服务端的响应都可以看做是一个消息,在理想化的RESTful 生态系统中,这些消息必须是自描述的。
良好的反馈对于实现的验证是积极的,错误实现产生的消息可以帮助用户调试和纠正使用产品的不正确方式。对于API, 错误信息是使用API上下文的良好方式之一。
调整你的错误与标准HTTP代码一致。客户端引发的错误应该使用400类型错误,如果是服务端的错误应该使用500类型来响应。 一个对资源操作成功后应该返回一个200类型的响应。
有很多的响应代码。想了解更多, 看看这个REST API教程 .
一般来说,使用你的API时有三种可能就结果:
- 客户端应用程序的行为是错误的(客户端错误–4xx响应代码)
- API行为错误 (服务器错误- 5 xx响应代码)
- 客户端和API工作正常 (成功– 2xx响应代码)
成功解决客户使用你的API时遇到的问题将大大改善开发人员使用体验和防止滥用API。 详细描述这些错误,同时保持简明和整洁。在错误消息中提供足够的信息有助于用户解决它们的问题,如果你觉得需要更加详细的信息,最好另写文档并在此处提供链接。
GET 响应例子
一个良好设计的API应该有响应示例,以明白是否成功调用了一个URL。响应示例应该简单、简洁和易于理解的。 一个好的经验法则是:帮助开发人员在5秒内理解一个成功的响应。回到我们的照片分享应用,我们定义了 /users 和 /photos URL。 /users 应该易数组的形式提供所有注册的用户,并且包含用户名称和加入日期属性。
你可以在Swagger(OpenAPI)中使用 API设计工具 来定义你的API,详述如下:
responses
:
200
:
description
: Successfully returned information about users
schema
:
type
: array
items
:
type
: object
properties
:
username
:
type
:
"string"
example
:
"kesh92"
created_time
:
type
:
"dateTime"
example
:
"2010-01-12T05:23:19+0000"
注意数据类型和实例的每个响应项注释,最终用户期望的是一个成功的GET调用。成功响应后最终用户将接收的JSON看起来如下:
{
“data”:[
{
“Username”:“example_user1”,
“created_time
":“2013-12-23T05:51:14+0000 ”
},
{
“username”:“example_user2”,
“created_time"
:“
2015
-3
-19
T17:51:15+0000 ”
}
….
]
}
如果用户调用了这个方法,就应该获得包含上述数据和一个说明正确调用了的200响应状态码。 同样的,,一个不正确的调用应该产生适当的400 或500 响应状态码和其它相关信息,以帮助用户更好地操作。
请求
优雅的处理复杂性
你试图开放的数据包含大量的有利于用户的属性,这些属性描述的基本资源和隔离特定信息,可以通过适当的方法来操作。
一个API应该努力提供完整的信息、数据和资源来帮助开发者以无缝的方式与之整合。
然而, 完整意味着对你的API考虑通用使用情况。可能会有许多这样的关系和属性,单独为他们定义资源不是好的做法。
资源暴露的数据量也应考虑。如果你暴露得太多,这会对服务器产生消极的影响,特别是对于负载和性能。
上述情况和关系是在设计的API时需要重点考虑的因素,可以使用适当的参数来处理。你可以扫描查询参数中limit参数来限制响应数据量,或者让客户端使用路径参数来隔离数据。
以我们的照片分享应用作为示例。
它可以用于开发者获取在特定位置和特定主题标签中共享的所有照片的信息。 您可能还想要通过将每个 API 调用的结果数限制为 10,以减轻服务器负载。 如果最终用户想要找到波士顿的所有照片,并使用 winter 标签,则请求将是:
GET /photos?location=boston&hashtag=winter&
limit
=10
注意现在的复杂性如何被简化为一个与查询参数的简单关联。如果您想根据客户的请求提供特定用户的信息,则调用:
GET
/users/kesh92
这里的 kesh92 是一个指定的用户名,它会返回该用户的地点和加入日期。
这只是朝着API完备性进行参数设计的几种方式,可以帮助用户更直观的使用你的API。
最后, 有疑问时,暂时离开它。如果你重新思考了某个资源或集合的功能,应该把它放入下一个迭代中。开发和维护API是一个持续的过程,等待正确的用户反馈可以构建一个健壮的API,以帮助用户以创造性的方式集成和开发应用程序。
API设计入门
没有一个API设计方法能够一劳永逸解决所有组织的问题。上述的建议仅仅是参考意见和建议,能否采用取决于你的用户情况和需求。
一个API设计至关重要的主要原因是你的API能帮助到终端用户,他们的需求就是贯穿你整个API设计的指明灯。
原作者:Keshav Vasudevan ,译者: luke , 小吕 , 卞卞 , abel533
End.