REST命名约定与按组分类

huangapple go评论69阅读模式
英文:

rest naming convention with group by

问题

我正在处理一个必须按“州”分组返回“所有可用城市”的 REST 端点。
我返回以下对象:

@Builder
@Data
class CitiesByState
{
	Map<String, List<Cities>> citiesByStateName;
}

一切工作正常,没有任何问题,但是我被命名约定困住了。对于这种类型的端点,最佳的命名约定是什么?

http://url/api/cities?group-by=state
http://url/api/state/cities

英文:

I'm working on rest endpoint which must returns "all availables cities" grouping by "state".
I returns the following object:

@Builder
@Data
class CitiesByState
{
	Map&lt;String, List&lt;Cities&gt;&gt; citiesByStateName;
}

Everything work without any issue but. I'm block with naming convention. What is the best naming convention for this kind of endpoint ?

http://url/api/cites?group-by=state
http://url/api/state/cities

?

答案1

得分: 2

自从State name被用作键之后,

我更倾向于使用
http://url/api/states/{statename}/cities,这也支持REST的cacheable约束。

关于这方面的许多内容已在这里有详细描述。

英文:

Since State name is used as key

I would prefer
http://url/api/states/{statename}/cities, which also enables cacheable constraint of REST.

A lot on this has been described here

答案2

得分: 0

假设您有一个收藏资源 /cities,其中列出了所有城市。

进一步假设一个 city 具有许多属性(例如 statepopulation 等)。

作为客户端(REST 消费者,如基于 JavaScript 的 Web 应用程序),您不希望具有 可以选择分组的属性 吗?

将资源与由 URI 标识的表示耦合

您的方法通过预定义此 cities 资源表示的 变体 来限制了这种灵活性。例如 /cities?by-state。但这将导致固定耦合,因为分组现在取决于客户端和服务器的实现。每次您在客户端针对某个用例更改分组时,您都必须同时调整服务器端。

将分组委托给客户端

Fielding 在 5.1.2 客户端-服务器 中应用了 关注点分离 原则:

> 关注点分离是客户端-服务器约束背后的原则。通过将 用户界面 关注点与 数据存储 关注点分开,我们提高了用户界面在多个平台上的可移植性,并通过简化服务器组件来提高可扩展性。

好处:通过在 客户端上执行分组,您将变得更加灵活。
应用这种 关注点分离 将客户端与服务器解耦:

  1. 服务器端接口提供对存储数据的 访问. 在这里:原始城市列表通过 /cities 获得。也许分别为可用的分组提供资源,可以在每个城市内部作为 属性 出现:/states
  2. 客户端框架(无论是 Python 脚本还是 JavaScript Web 应用程序)可以对数据进行分组,将一个 简单 的城市列表转换为分组列表、树、映射或其他任何形式。

客户端如何分组:
以下是 JavaScript 伪代码,受到 javascript - Most efficient method to groupby on an array of objects - Stack Overflow 的启发:

const groupBy = (x, f) => x.reduce((a, b) => ((a[f(b)] || []).push(b), a), {});

var cities = restApi.get("/cities");
var citiesGroupedByState = groupBy(cities, c => c.state);

哪些约定?

无论是 REST(Roy Fielding 的论文)还是 RFC 3986(Tim Berners-Lee 编写),都没有预见到命名约定:

> 路径组件包含数据,通常以分层形式组织,与非分层查询组件中的数据一起(第 3.4 节),用于标识资源[..]

您可以在澳大利亚政府的 API 标准中看到这些约定的实现,其中的 命名约定 部分:

> URL 必须遵循以下标准命名约定:
>&gt; /namespace/project-name/v1/collection?attributes=first_name,last_name &gt; \___________________________________/\______________________________/ &gt; | | &gt; path query &gt;

而且您可能会问,在查询 URL 时,客户端如何请求特定的表示形式(响应类型,如分组的 Map)?

Untangled - musings of Roy T. Fielding 中有答案,REST APIs must be hypertext-driven

> REST API 不应该有对客户端有意义的“类型化”资源。规范的作者可以使用资源类型来描述接口背后的服务器实现,但这些类型对于客户端来说必须是无关紧要且不可见的。对于客户端而言,唯一重要的类型是当前表示的媒体类型和标准化的关系名称。

英文:

Assume you have a collection resource /cities which lists all cities.
Assuming further a city has many attributes (like state, population, etc.).

Wouldn't you as a client (the REST consumer, like a JavaScript driven web-app) like to have the choice for which attribute to group ?

Coupling the resource to a representation identified by URI

Your approach restricts that flexibility by predefining a variant for this cities resource's representation.
Like /cities?by-state. But that would dictate fixed-coupling, because grouping now depends on the client and the server's implementation too. Every time you change grouping on the client side for a use-case, you would have to adjust the server side too.

Delegate grouping to the client

Fielding applied separation of concerns in 5.1.2 Client-Server:

> Separation of concerns is the principle behind the client-server constraints. By separating the user interface concerns from the data storage concerns, we improve the portability of the user interface across multiple platforms and improve scalability by simplifying the server components.

Benefit: You would stay much more flexible by performing the grouping on client-side.
Applying that separation of concerns decouples the client from the server:

  1. The server-side interface provides access to stored data. Here: the raw list of cities by /cities. Maybe separately a resource for groups available, that may appear as attribute inside each city: /states.
  2. The client-side framework (be it a Python script or JavaScript web-app) can group the data, transform a simple list of cities into a grouped list, tree, map, or whatever.

How the client could group:
Following JavaScript pseudo-code, inspired by javascript - Most efficient method to groupby on an array of objects - Stack Overflow:

const groupBy = (x,f)=&gt;x.reduce((a,b)=&gt;((a[f(b)]||=[]).push(b),a),{});

var cities = restApi.get(&quot;/cities&quot;);
var citiesGroupedByState = groupBy(cities, c =&gt; c.state)

Which Conventions?

Neither REST (in dissertation by Roy Fielding), nor the RFC 3986 (along Tim Berners-Lee) foresee naming conventions:

> The path component contains data, usually organized in hierarchical form, that, along with data in the non-hierarchical query component (Section 3.4), serves to identify a resource [..]

See them implemented for example in API Standards of the Australian Government, section Naming Conventions:

> URLs MUST follow the standard naming convention as described below:
>
&gt; /namespace/project-name/v1/collection?attributes=first_name,last_name
&gt; \___________________________________/\______________________________/
&gt; | |
&gt; path query
&gt;

And you may ask, how can a client request a specific representation (response type like a grouped Map) when querying an URL?

Answered in Untangled - musings of Roy T. Fielding, REST APIs must be hypertext-driven:

> A REST API should never have “typed” resources that are significant to the client. Specification authors may use resource types for describing server implementation behind the interface, but those types must be irrelevant and invisible to the client. The only types that are significant to a client are the current representation’s media type and standardized relation names.

huangapple
  • 本文由 发表于 2020年9月17日 21:08:16
  • 转载请务必保留本文链接:https://go.coder-hub.com/63938729.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定