良好的API设计是那些试图完善其API策略的团队经常讨论的话题。在之前的一篇博客文章中,我简要讨论了API设计的重要性。设计良好的API的好处包括:提升开发者体验、加快文档编写速度以及提高API的采用率。 但是,究竟什么是好的API设计呢?在这篇博客文章中,我将详细介绍一些设计RESTful API的最佳实践。
设计良好的API的特点
一般来说,有效的API设计将具有以下特点
-
- 易于阅读和使用: 设计良好的API将易于使用,并且其资源和相关操作可以被经常使用它的开发者快速记忆。
- 难以误用: 实现和集成设计良好的API将是一个简单的过程,编写错误代码的可能性较小。它提供信息丰富的反馈,并且不会对API的最终消费者施加严格的指导方针。
- 完整而简洁: 最后,一个完整的API将使开发者能够针对您公开的数据构建功能齐全的应用程序。完整性通常是随着时间推移而实现的,大多数API设计者和开发者在现有API的基础上逐步构建。它是每个拥有API的工程师或公司都必须努力实现的目标。
为了阐述以下概念,我将以一个照片分享应用为例。该应用允许用户上传照片,并用照片拍摄地点和描述照片相关情感的标签对其进行特征化。
集合、资源及其URL
理解资源和集合
资源是REST概念的基础。资源是一个足够重要以至于可以独立引用的对象。资源包含数据、与其他资源的关系以及对其进行操作以访问和操作相关信息的方法。 一组资源称为集合。集合和资源的内容取决于您的组织和消费者需求。例如,如果您认为市场将从获取产品用户群的基本信息中受益,那么您可以将其作为集合或资源公开。 统一资源定位符(URL)标识资源的在线位置。此URL指向您的API资源存在的位置。基本URL是此位置的固定部分。 在照片分享应用中,我们可以通过集合和资源公开有关使用该应用的用户数据,并通过相应的URL进行访问。
- /users: 一个用户集合
- /users/username1: 一个包含特定用户信息资源的
名词更好地描述URL
基本URL应该整洁、优雅和简单,以便使用您产品的开发者可以在其Web应用程序中轻松使用它们。一个冗长且难以阅读的基本URL不仅看起来不好,而且在尝试重写时也容易出错。名词应该始终被信任。 资源名词保持单数或复数没有硬性规定,但建议将集合保持为复数。在所有资源和集合中分别保持相同的复数形式是良好的实践。 保持这些名词的自解释性有助于开发者从URL中理解所描述的资源类型,这最终可以使他们在使用您的API时实现自给自足。 回到照片分享应用,假设它有一个公共API,其中/users和/photos作为集合。注意它们都是复数名词吗?它们也是自解释的,我们可以推断出/users和/photos分别提供了产品注册用户群和分享照片的信息。
用HTTP方法描述资源功能
所有资源都有一组可以对其进行操作的方法,以处理API公开的数据。 RESTful API主要由HTTP方法组成,这些方法对任何资源都有明确定义和独特的行为。以下是定义RESTful API中任何资源或集合的CRUD操作的常用HTTP方法列表。
方法 |
描述 |
GET |
用于检索资源的表示。 |
POST |
用于创建新资源和子资源 |
PUT |
用于更新现有资源 |
PATCH |
用于更新现有资源 |
DELETE |
用于删除现有资源 |
(如果您想了解PUT和PATCH之间的区别,请查看StackOverflow上的此帖。) 在URL中避免使用动词也是个好主意。GET、PUT、POST和DELETE操作已用于对URL描述的资源进行操作,因此在URL中使用动词而不是名词可能会使资源操作变得混乱。 在照片分享应用中,以/users和/photos作为端点,您的API最终消费者可以直观地使用上述RESTful CRUD操作轻松地使用它们。
响应
提供反馈以帮助开发者成功
向开发者提供关于他们产品使用情况的良好反馈,对于提高采用率和留存率大有裨益。 每个客户端请求和服务器端响应都是一个消息,在理想的RESTful生态系统中,这些消息必须是自描述的。 良好的反馈包括对正确实现的积极验证,以及对不正确实现的信息性错误,这可以帮助用户调试和纠正他们使用产品的方式。对于API而言,错误是提供API使用上下文的好方法。 您的错误应与标准HTTP代码保持一致。不正确的客户端调用应与400类型的错误相关联。如果存在任何服务器端错误,则必须关联适当的500响应。对您的资源成功使用的方法应返回200类型的响应。 响应代码有很多。如需更多信息,请查看此REST API教程。 通常,使用您的API时有三种可能的结果:-
- 客户端应用程序行为错误(客户端错误 - 4xx响应代码)
- API行为错误(服务器错误 - 5xx响应代码)
- 客户端和API正常工作(成功 - 2xx响应代码)
无论何时您的最终消费者在使用API时遇到障碍,引导他们走向成功将大大改善开发者体验并防止API误用。良好地描述这些错误响应,但要保持简洁明了。在错误代码中提供足够的信息,以便最终用户可以开始修复原因,如果您认为需要更多信息,请提供指向额外文档的链接。
为所有GET响应提供示例
设计良好的API还应包含成功调用URL后预期响应的示例。此示例响应应简单、明了、易于理解。一个好的经验法则是,帮助开发者在五秒内准确理解成功响应会给他们带来什么。 回到我们的照片分享应用,我们已经定义了/users和/photos URL。/users集合将以数组形式提供所有已注册用户的用户名和注册日期。 您可以使用API设计工具,按照如下方式在Swagger (OpenAPI) 规范中定义您的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-19T17:51:15+0000 ”
}
….
]
}
如果最终用户成功地使用GET方法调用该端点,用户应该获得上述数据以及200响应代码,以验证正确的使用。同样,不正确的调用应该产生适当的400或500响应代码,并附带相关信息,以帮助用户更好地操作该集合。
请求
优雅地处理复杂性
您试图公开的数据可以通过许多属性来表征,这些属性可能对使用您的API的最终消费者有益。这些属性描述了基本资源,并隔离了可以使用适当方法进行操作的特定信息资产。 API应努力实现完整性,并提供所有必需的信息、数据和资源,以帮助开发者无缝地集成。 但完整性意味着要考虑API的常见用例。可能存在许多这样的关系和属性,为每个属性定义资源并不是一个好的实践。 资源公开的数据量也应考虑在内。如果您试图公开大量数据,可能会对服务器产生负面影响,尤其是在负载和性能方面。 上述情况和关系是API设计中的重要考虑因素,可以使用适当的参数来处理。您可以在查询参数中使用“?”来包含属性和限制响应,或者使用路径参数来隔离客户端正在处理的数据的特定组件。 让我们以我们的照片分享应用为例。 对开发者而言,获取特定位置和特定标签下所有分享照片的信息可能很有用。您还希望将每次API调用的结果数量限制为10个,以防止服务器负载过重。如果最终用户想查找波士顿(Boston)所有带有#winter标签的照片,调用将是:
GET /photos?location=boston&hashtag=winter&limit=10
注意到复杂性现在已被简化为与查询参数的简单关联。如果您想根据客户端请求提供特定用户的信息,调用将是
GET /users/kesh92
其中kesh92是users集合中特定用户的用户名,将返回kesh92的所在地和加入日期。 这些只是您可以设计参数以实现API完整性并帮助您的最终开发者直观使用API的一些方法。 最后,如果有所疑虑,就暂时搁置。如果您对某个特定资源或集合的功能有疑虑,那么就把它留到下一个迭代。开发和维护API是一个持续的过程,等待正确用户的反馈对于构建一个强大的API大有裨益,该API能让用户以创造性的方式集成和开发应用程序。
开始API设计
没有一种API设计方法适用于所有组织。以上建议仅供参考—您可以根据自己的用例和需求采用或舍弃这些建议和推荐。 API设计至关重要的主要原因之一是帮助最终消费者使用您的API。他们的需求应成为设计和构建优秀API的指路明灯。
感谢您的阅读!正在寻找更多API资源?订阅Swagger通讯。每月接收一封包含我们最佳API文章、培训、教程等的电子邮件。 订阅