非常赞的四篇文章:

本篇阅读目录:

  • 1. HTTP Methods
  • 2. JSON API 命名规则
  • 3. API URI design
  • 4. WebAPI 使用 snake_case 还是 camelCasing?

1. HTTP Methods

HTTP 常用方法:

  • GET: 获取某个资源。
  • POST: 创建一个新的资源。
  • PUT: 替换某个已有的资源。
  • PATCH: 修改某个已有的资源。
  • DELETE:删除某个资源。

我原先以为修改某一个资源,也是用 POST,后来发现还有一个 PATCH,但发现 HttpClient 并没有提供此调用方法,需要我们进行扩展:

public static class HttpClientExtensions
{
public static async Task<HttpResponseMessage> PatchAsync(this HttpClient client, Uri requestUri, HttpContent iContent)
{
var method = new HttpMethod("PATCH");
var request = new HttpRequestMessage(method, requestUri)
{
Content = iContent
}; HttpResponseMessage response = new HttpResponseMessage();
try
{
response = await client.SendAsync(request);
}
catch (TaskCanceledException e)
{
Debug.WriteLine("ERROR: " + e.ToString());
} return response;
}
}

调用代码:

HttpContent httpContent = new StringContent("Your JSON-String", Encoding.UTF8, "application/json");
var responseMessage = await httpClient.PatchAsync(new Uri("testUri"), httpContent);

2. JSON API 命名规则

相关阅读:You should use camelCase with JSON, but snake_case is 20% easier to read

camelCase(骆驼命名)我们都非常熟悉,因为 C# 就是使用的这个命名法,snake_case(蛇形命名)适用于 python 和 ruby,比如商品 ID,camelCase 会命名为 productId,snake_case 则会命名为 product_id。

需要注意的是,snake_case 只限于 JSON API 命名,并不限于 URI,URI 中一般也不会使用下划线,为什么要对 JSON API 进行规范命名?因为 RESTful 是无状态风格,也就是说 RESTful API 并不限于某一种客户端进行调用,所以 JSON API 的命名必须要规范,如果只是 C# 调用的话,那么命名采用 camelCase 命名就可以了,但显然并不是这样,最后得出的结论是使用 snake_case 命名会比较好,以后在设计的时候,需要注意了。

3. API URI design

API URI 设计最重要的一个原则:nouns (not verbs!),名词(而不是动词)。

CRUD 简单 URI:

  • GET /users - 获取用户列表
  • GET /users/1 - 获取 Id 为 1 的用户
  • POST /users - 创建一个用户
  • PUT /users/1 - 替换 Id 为 1 的用户
  • PATCH /users/1 - 修改 Id 为 1 的用户
  • DELETE /users/1 - 删除 Id 为 1 的用户

上面是对某一种资源进行操作的 URI,那如果是有关联的资源,或者称为级联的资源,该如何设计 URI 呢?比如某一用户下的产品:

  • GET /users/1/products - 获取 Id 为 1 用户下的产品列表
  • GET /users/1/products/2 - 获取 Id 为 1 用户下 Id 为 2 的产品
  • POST /users/1/products - 在 Id 为 1 用户下,创建一个产品
  • PUT /users/1/products/2 - 在 Id 为 1 用户下,替换 Id 为 2 的产品
  • PATCH /users/1/products/2 - 修改 Id 为 1 的用户下 Id 为 2 的产品
  • DELETE /users/1/products/2 - 删除 Id 为 1 的用户下 Id 为 2 的产品

还有一种情况,我们一般在设计 API 的时候,会进行一些查询操作,比如分页和排序等,API 方法参数设计可能很容易,那重要的 URI 该如何设计呢?我们先看这样的一个设计:

[HttpGet]
[Route("api/wzlinks/users-{spaceUserId}/{pageIndex=1}/{pageSize=20}")]
public async Task<IEnumerable<WzLinkDTO>> GetPagedList(int spaceUserId, int pageIndex, int pageSize)
{
.....
}

首先,这个 URI 想要表示的意思是:获取某一用户下,分页查询的网摘列表,这个 API 设计好不好呢?我们看下 GitHub 中的一个 API:

"current_user_repositories_url": "https://api.github.com/user/repos{?type,page,per_page,sort}"

差别是不是很大?而且我们设计的 URI 表达也比较混乱,查询应该是参数,并且是对 URI 进行的查询,所以放在 URI 中会不太合适,我们完善下:

[HttpGet]
[Route("api/users/{space_user_id}/wzlinks")]
public async Task<IEnumerable<WzLinkDTO>> GetPagedList(int space_user_id, int page, int per_page)
{
.....
}

URI 表达为:获取 space_user_id 为 1 用户下的网摘分页列表,上面设计会不会更好些呢?调用示例:

api.cnblogs.com/api/users/1/wzlinks?page=1&per_page=20

GitHub API(规范参考):https://api.github.com

{
"current_user_url": "https://api.github.com/user",
"current_user_authorizations_html_url": "https://github.com/settings/connections/applications{/client_id}",
"authorizations_url": "https://api.github.com/authorizations",
"code_search_url": "https://api.github.com/search/code?q={query}{&page,per_page,sort,order}",
"emails_url": "https://api.github.com/user/emails",
"emojis_url": "https://api.github.com/emojis",
"events_url": "https://api.github.com/events",
"feeds_url": "https://api.github.com/feeds",
"following_url": "https://api.github.com/user/following{/target}",
"gists_url": "https://api.github.com/gists{/gist_id}",
"hub_url": "https://api.github.com/hub",
"issue_search_url": "https://api.github.com/search/issues?q={query}{&page,per_page,sort,order}",
"issues_url": "https://api.github.com/issues",
"keys_url": "https://api.github.com/user/keys",
"notifications_url": "https://api.github.com/notifications",
"organization_repositories_url": "https://api.github.com/orgs/{org}/repos{?type,page,per_page,sort}",
"organization_url": "https://api.github.com/orgs/{org}",
"public_gists_url": "https://api.github.com/gists/public",
"rate_limit_url": "https://api.github.com/rate_limit",
"repository_url": "https://api.github.com/repos/{owner}/{repo}",
"repository_search_url": "https://api.github.com/search/repositories?q={query}{&page,per_page,sort,order}",
"current_user_repositories_url": "https://api.github.com/user/repos{?type,page,per_page,sort}",
"starred_url": "https://api.github.com/user/starred{/owner}{/repo}",
"starred_gists_url": "https://api.github.com/gists/starred",
"team_url": "https://api.github.com/teams",
"user_url": "https://api.github.com/users/{user}",
"user_organizations_url": "https://api.github.com/user/orgs",
"user_repositories_url": "https://api.github.com/users/{user}/repos{?type,page,per_page,sort}",
"user_search_url": "https://api.github.com/search/users?q={query}{&page,per_page,sort,order}"
}

4. WebAPI 使用 snake_case 还是 camelCasing?

补充:因为 space_user_id 违反 C# 的命名规则,Google 搜索“asp net web api snake_case”,却搜多到大量的“camelCasing”关键字,而且在微软大部分 WebAPI 示例中,Route 的参数命名设计规范都是 camelCasing,所以。。。。没办法,只能使用 camelCasing 命名规则吧,谁让用的是 .NET 呢,不过,有人还搞了个 SnakeCaseFormUrlEncodedMediaTypeFormatter 扩展,但好像是在过程中进行了转化,并不是解决定义问题。

网摘的 API 我们再修改下:

[HttpGet]
[Route("api/users/{spaceUserId}/wzlinks")]
public async Task<IEnumerable<WzLinkDTO>> GetPagedList(int spaceUserId, int page, int perPage)
{
.....
}

不经意间,还发现 ASP.NET WebAPI Help 一个有意思的地方,比如上面的 API 设计,得到的是这样的 Help 说明:

如果我们把 API 代码修改成:

[HttpGet]
[Route("api/users/{space_user_id}/wzlinks")]
public async Task<IEnumerable<WzLinkDTO>> GetPagedList(int spaceUserId, int page, int perPage)
{
.....
}

得到的却是这样的 Help 说明:

发现有什么不同了吗?看来 ASP.NET WebAPI Help 还是蛮智能的呢。

RESTful API URI 设计的一些总结的更多相关文章

  1. RESTful API URI 设计: 查询(Query)和标识(Identify)

    相关文章:RESTful API URI 设计的一些总结. 问题场景:删除一个资源(Resources),URI 该如何设计? 应用示例:删除名称为 iPhone 6 的产品. 是不是感觉很简单呢?根 ...

  2. RESTful API URI 设计: 判断资源是否存在?

    相关的一篇文章:RESTful API URI 设计的一些总结. 问题场景:判断一个资源(Resources)是否存在,URI 该如何设计? 应用示例:判断 id 为 1 用户下,名称为 window ...

  3. 好RESTful API的设计原则

    说在前面,这篇文章是无意中发现的,因为感觉写的很好,所以翻译了一下.由于英文水平有限,难免有出错的地方,请看官理解一下.翻译和校正文章花了我大约2周的业余时间,如有人愿意转载请注明出处,谢谢^_^ P ...

  4. RESTful API的设计原则

    好RESTful API的设计原则   说在前面,这篇文章是无意中发现的,因为感觉写的很好,所以翻译了一下.由于英文水平有限,难免有出错的地方,请看官理解一下.翻译和校正文章花了我大约2周的业余时间, ...

  5. 好的RESTful API的设计原则

    转载自一位大佬 英文原版 Principles of good RESTful API Design Good API design is hard! An API represents a cont ...

  6. [Medium翻译]RESTful API权威设计指南-设计更好的API

    本文为授权译文.希望查看原文的同学请戳链接:https://hackernoon.com/restful-api-design-step-by-step-guide-2f2c9f9fcdbf 对于我们 ...

  7. Restful API的设计与实践

    Restful这个名称应该很多人都不陌生,但是我发现不少人对Restful存在或多或少的理解偏差,其中不泛比较厉害的程序员,所以有必要为Restful来“正名”. Restful是一种软件架构风格,设 ...

  8. [转]10个有关RESTful API良好设计的最佳实践

    Web API已经在最近几年变成重要的话题,一个干净的API设计对于后端系统是非常重要的. 通常我们为Web API使用RESTful设计,REST概念分离了API结构和逻辑资源,通过Http方法GE ...

  9. 10个有关RESTful API良好设计的最佳实践

    Web API已经在最近几年变成重要的话题,一个干净的API设计对于后端系统是非常重要的. 通常我们为Web API使用RESTful设计,REST概念分离了API结构和逻辑资源,通过Http方法GE ...

随机推荐

  1. Linux程序包管理之yum及源代码安装

    第十六章.Linux程序包管理之yum及源代码安装 目录 yum介绍 yum配置文件 yum的repo配置文件中可用的变量 yum命令的使用 使用光盘作为本地yum仓库 如何创建yum仓库 编译安装的 ...

  2. linux下创建文件与目录时默认被赋予了什么样的权限?

    当我们创建一个新的文件或目录的时候,他的默认权限是什么? umask--指定当前使用者在创建文件或目录的时候默认的权限值 [root@iZ288fgkcpkZ default]# umask [roo ...

  3. Jenkins——构建、集成中的问题

      准备 Jekins   安装插件 MsBuild Plugin Team Foundation Server Plug-in 配置环境变量 我的电脑中设置环境变量,Path中添加msbuild的路 ...

  4. HDOJ 2111. Saving HDU 贪心 结构体排序

    Saving HDU Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total ...

  5. Morris post order traversal algorithm

    Sept. 5, 2015 花时间把代码读明白, 比光看书强. 动手写代码, 改代码,  兴趣是最好的老师. 多记几个例子, 增加情趣. 举个例子关于中序遍历,            4       ...

  6. Js函数function基础理解

    正文:我们知道,在js中,函数实际上是一个对象,每个函数都是Function类型的实例,并且都与其他引用类型一样具有属性和方法.因此,函数名实际上是指向函数对象的指针,不与某个函数绑定.在常见的两种定 ...

  7. [LeetCode] Number of Connected Components in an Undirected Graph 无向图中的连通区域的个数

    Given n nodes labeled from 0 to n - 1 and a list of undirected edges (each edge is a pair of nodes), ...

  8. 撸一段 SQL ? 还是撸一段代码?

    记得刚入公司带我的研发哥们能写一手漂亮的 SQL,搜索准确.执行快.效率高. 配合Web项目中的查询展示数据的需求,基本是分分钟完成任务. 那段时间基本是仰视的态度,每天都去讨教一点手写 SQL 的要 ...

  9. 浏览器控制台命令调试——console

    控制台命令调试时通过浏览器开发工具中的控制台命令嵌入到JavaScript中,输出特定的信息或日志,从而达到调试的目的. 我们常用的Chrome和FireFox,都可以通过F12来打开开发工具. 下面 ...

  10. 【应用】_有道词典客户端一个后缀名为sql的数据库。

    [缘起] 在清理电脑磁盘的时候,看一看各安装文件夹有占用了多大容量,发现有道词典居然达140MB了,于是进去看看. 发现个有趣的文件:XXX.sql. 首先我们看一看它的安装文件夹的结构: Dict ...