rest api设计_在设计REST API时如何平衡粗俗与闲谈

rest api设计

by Suhas Chatekar

由Suhas Chatekar

在设计REST API时如何平衡粗俗与闲谈 (How to balance chunkiness against chattiness when designing your REST API)

One of the challenges of building any API is that you don’t know who will use your API, or how they will use it.

构建任何API的挑战之一是您不知道谁将使用您的API或他们将如何使用它。

You may have an internal consumer who calls your API over a LAN connection. This consumer would not mind making massive API responses (chunky), or making several API calls to get all the different chunks of data that they want (chatty).

您可能有一个内部使用者,他通过LAN连接来调用您的API。 该用户不介意进行大量的API响应(块状),或进行几次API调用来获取他们想要的所有不同数据块(闲谈)。

Or you may have an external consumer connecting over the internet. This consumer would like to make a small number of network calls. Such consumers also want the API to return just enough data.

或者您可能有外部消费者通过Internet连接。 该用户希望进行少量的网络呼叫。 此类使用者也希望API返回足够的数据。

Consumers connecting from a mobile network are particular about network calls. For them, network calls result in carrier charges for their users. Large amount data returned by APIs is not ideal for them as it may lead to a lot of battery usage while processing it.

从移动网络进行连接的消费者对网络呼叫特别关注。 对于他们来说,网络通话会为其用户收取运营商费用。 API返回的大量数据对于它们而言并不理想,因为在处理过程中可能会导致大量电池消耗。

As an API developer, you do not get to decide whether your API should be chatty or chunky or none. Consumers of your API want to decide that. Truth is, most APIs have consumers from both the camps. So how do you deal with these demands? The easy answer is by giving more power to the consumers of your APIs. Let the consumers be in the driving seat and let them tell your API what do they want.

作为API开发人员,您不必决定您的API是应该是健谈还是矮胖的,或者根本不应该。 API的使用者希望决定这一点。 事实是,大多数API都有两个阵营的消费者。 那么您如何处理这些需求? 简单的答案是为API使用者提供更多功能。 让消费者坐在驾驶席上,让他们告诉您的API他们想要什么。

In this article, I am going to talk about three techniques that let you do that.

在本文中,我将讨论让您做到这一点的三种技术。

方法1:使用懒惰的Get来控制有效负载的大小 (Technique 1: Use Lazy Get to control the size of your payload)

Most Object Relational Mapper(ORM) tools have a feature called Lazy Loading. ORMs use this feature to return only the top level entity when they execute a SQL script. Any associated entities are not loaded completely but only their identifiers are loaded. When the application tries to access the associated entity, the ORM kicks in. It loads that entity using its identifier which it had loaded earlier. This is smart because ORM is not guessing when the application needs what. Instead, it is giving the application an ability to fetch on demand what’s needed when.

大多数对象关系映射器(ORM)工具都具有称为延迟加载的功能。 ORM在执行SQL脚本时使用此功能仅返回顶级实体。 任何关联的实体都不会完全加载,而只会加载它们的标识符。 当应用程序尝试访问关联的实体时,ORM会加入。它使用先前已加载的标识符来加载该实体。 这很聪明,因为ORM不会猜测应用程序何时需要什么。 相反,它使应用程序能够按需获取所需的时间。

Lazy Get is similar. With Lazy Get, you do do not return a linked resource by default. Instead, you return a shallow version with only top level attributes populated. The API consumer can

懒惰获取类似。 使用惰性获取,默认情况下您不返回链接资源。 相反,您将返回仅填充顶级属性的浅表版本。 API使用者可以

  1. Instruct the server to return the linked resources in the same response

    指示服务器以相同的响应返回链接的资源
  2. Retrieve the linked resources at a later time using the link returned in the original response

    稍后使用原始响应中返回的链接来检索链接的资源

This is best explained with an example. Let’s say we are building a meetup platform. People can create interest group and host meetups using our platform. Members of the platform can

最好用一个例子来解释。 假设我们正在建立一个聚会平台。 人们可以使用我们的平台创建兴趣小组并主持聚会。 该平台的成员可以

  1. Join the groups they like

    加入他们喜欢的团体
  2. Connect with other members of the platform

    与平台的其他成员联系
  3. RSVP for the events hosted by various groups

    RSVP处理各团体举办的活动

This is a set of basic features any meetup platform can have.

这是任何聚会平台均可拥有的一组基本功能。

This platform is API enabled and we have got an API method to retrieve a member resource which looks like below.

该平台已启用API,我们有一个API方法来检索member资源,如下所示。

For brevity, the above code does not show the full representation of memberships, rsvps and friends resources. In reality, these resources will have more attributes than what I am showing here. They could even have their own linked resources.

为简便起见,以上代码未完整显示membershipsrsvpsfriends资源。 实际上,这些资源将具有比我在此处显示的资源更多的属性。 他们甚至可以拥有自己的链接资源。

A consumer of this API may not need all of this data all the time. A consumer connecting over LAN would happily accept a lot of data returned. But a mobile app developer connecting over a slow internet connection would not want this. Guess what? You can implement Lazy Get on this API method and let the consumer decide what data they want to be returned. You do this by supporting a new query parameter named expand. This parameter accepts comma separated names of the linked resources that the consumer wants the server to return. So for example, if the URL for retrieving the above member resource was

此API的使用者可能一直不需要所有这些数据。 通过LAN连接的用户将很高兴接受许多返回的数据。 但是,通过慢速Internet连接进行连接的移动应用程序开发人员不希望这样做。 你猜怎么了? 您可以在此API方法上实现惰性获取,并让使用者确定要返回的数据。 为此,您需要支持一个名为expand的新查询参数。 此参数接受使用者希望服务器返回的链接资源的逗号分隔名称。 因此,例如,如果用于检索上述成员资源的URL是

https://myapi.com/v1/member/34234

https://myapi.com/v1/member/34234

If a consumer wants only memberships information returned then they can send a request to the following URL

如果消费者只希望返回会员信息,那么他们可以向以下网址发送请求

https://myapi.com/v1/member/34234?expand=memberships

This is good. Now the consumer has a control over what data server returns. But what happens to other resources i.e. rsvps and friends? Is server just going to exclude them from the response? If server excludes them how does the consumer get those resources when it needs them?

很好 现在,使用者可以控制什么数据服务器返回。 但是其他资源( rsvpsfriends怎样? 服务器只是要将它们从响应中排除吗? 如果服务器将它们排除在外,那么消费者在需要它们时如何获得这些资源?

Instead, what server does is exactly same as what any ORM does with its lazy loading feature. The server returns an identifier of the resource in the place of the full resource.

相反,服务器执行的操作与任何ORM使用其延迟加载功能所做的操作完全相同。 服务器返回资源的标识符代替完整资源。

That way, if the consumer decides to fetch rsvps or friends resources, all they need to do is issue a GET request on the corresponding URLs.

这样,如果使用者决定获取rsvpsfriends资源,则他们要做的就是在相应的URL上发出GET请求。

使用超媒体使这一点变得更好 (Using hypermedia to make this little better)

In the previous example, how would a client fetch a friend resource with id 5678? Where would it get the actual URL to fetch this resource from?We can use hypermedia to help us here. If you have used hypermedia before then you may have guessed what I am talking about.

在前面的示例中,客户端将如何获取ID为5678的friend资源? 从哪里获取从中获取此资源的实际URL?我们可以在这里使用超媒体来帮助我们。 如果您以前使用过超媒体,那么您可能已经猜到我在说什么。

You can use one of the hypermedia specifications like Siren, HAL or Collection+JSON to return actual URL for the resource instead of just the id. If you are still at Richardson Maturity Model — Level 2 or below, don’t worry. You can do what we have done in such cases. We do not return the identifier of the linked resource. For out clients, it does not mean anything. We instead return an attributed href. This attribute contains the URL on which the clients can send a GET request to fetch that resource. The below is how our member resource looks with href attribute returned.

您可以使用SirenHALCollection + JSON之类的超媒体规范之一来返回资源的实际URL,而不仅仅是ID。 如果您仍处于2级或以下的Richardson成熟度模型 ,请不要担心。 在这种情况下,您可以做我们所做的事情。 我们不返回链接资源的标识符。 对于外出客户而言,这并不意味着什么。 相反,我们返回一个属性href 。 此属性包含客户端可以在其上发送GET请求以获取该资源的URL。 以下是返回了href属性的member资源的外观。

And we return this attribute by default for all our resources.

默认情况下,我们为所有资源返回此属性。

技术2:使用哈希API方法来减少闲聊 (Technique 2: Use a hash API Method to become less chatty)

Lazy Get is good for controlling the payload size of the response. Would it not be good to not have to make that API call again and again? It is, if the consumer caches the response it received.

惰性获取非常适合控制响应的有效负载大小。 不必一次又一次地调用该API会不好吗? 是的,如果使用者缓存收到的响应。

An obvious shortcoming of caching is you would not know when your cache becomes out of date. The server can return cache expiry information in the response headers. The consumer can bust the cache based on this information. But all you are doing here is moving the problem from client to server. The server is still guessing what is the latest time by which the cache must expire. Even worse is that most implementations would set this to a default value.

缓存的一个明显缺点是您不知道缓存何时过期。 服务器可以在响应头中返回缓存过期信息。 使用者可以根据此信息来破坏高速缓存。 但是您在这里所做的只是将问题从客户端转移到服务器。 服务器仍在猜测缓存必须过期的最新时间。 更糟糕的是,大多数实现会将其设置为默认值。

Hash API Method offers an alternative for the applications that

哈希API方法为以下应用程序提供了替代方法

  1. Cannot rely on caching as they always need to work on fresh copy of the data

    无法依赖缓存,因为它们始终需要处理数据的新副本
  2. Cannot make frequent and heavy API calls due to the environment they operate in i.e. mobile apps.

    由于它们在移动应用程序中运行的环境,因此无法频繁频繁地调用API。

A Hash API Method implementation will have the following

哈希API方法实现将具有以下内容

  1. Every resource that needs to support a Hash API Method must include a hash attribute

    每个需要支持哈希API方法的资源都必须包含哈希属性
  2. The value is of this attribute is the hash of the string (JSON/XML)representation of the resource

    该属性的值是资源的字符串(JSON / XML)表示形式的哈希值
  3. Server recalculates the hash every time the resource state changes.

    每次资源状态更改时,服务器都会重新计算哈希。
  4. A new API method to return the latest hash value for each resource

    一种新的API方法,可为每个资源返回最新的哈希值

Let’s say we want to support hash API method for the member resource from our previous example. So first we add a hash attribute as below

假设我们要为前面的示例中的成员资源支持哈希API方法。 所以首先我们添加如下的hash属性

The server uses a mechanism of its own choice to calculate the value of the hash attribute. It could also be a random string. The server must update its value every time the resource state changes.

服务器使用自己选择的机制来计算hash属性的值。 也可以是随机字符串。 每次资源状态更改时,服务器必须更新其值。

Next, we add the following new API method that returns the latest hash value for member resource

接下来,我们添加以下新的API方法,该方法返回成员资源的最新哈希值

https://myapi.com/v1/member/{memberid}/hash

This API method returns a response with the status of 200 OK. The response body contains the value of the hash attribute of the member resource. The key here is to make this API as fast as possible. The server can cache a map of resource id and hash value to reduce the response time.

此API方法返回状态为200 OK的响应。 响应主体包含成员资源的hash属性的值。 这里的关键是使此API尽可能快。 服务器可以缓存资源ID和哈希值的映射,以减少响应时间。

All that a bandwidth-conscious consumer has to do now is to make a call on the Hash API Method. It can then compare the returned hash value with the hash value it has from the previous retrieval of the resource. If the hash values are the same, then it is safe to assume that the resource has not changed since the consumer last retrieved it. If the hash values are different then it’s time to fetch the latest value of the resource.

注重带宽的消费者现在要做的就是调用Hash API方法。 然后,它可以将返回的哈希值与其从资源的先前检索中获得的哈希值进行比较。 如果哈希值相同,则可以安全地假设自使用者上次检索资源以来资源没有发生变化。 如果哈希值不同,那么该获取资源的最新值了。

始终保持哈希值的更新 (Keeping the hash updated all the times)

As more and more consumers start using hash API Method, it becomes important to ensure that hashes are always kept updated. This needs proper thinking and optimal design. Consider the following situations

随着越来越多的消费者开始使用哈希API方法,确保哈希始终保持更新就变得很重要。 这需要适当的思考和优化的设计。 考虑以下情况

  1. When a resource gets partially/fully updated, the hash must be updated

    当资源被部分/完全更新时,哈希必须更新
  2. If you hash includes the linked resources, the every time a resource gets updated, all the other resources that link this resource must update their hash.

    如果哈希包含链接的资源,则每次更新资源时,链接此资源的所有其他资源都必须更新其哈希。
  3. When a resource gets deleted, the the hash method for that resource must return a 404 Not Found and every consumer application should handle this response to delete their cached copy of the resource

    删除资源后,该资源的hash方法必须返回404 Not Found并且每个使用者应用程序都应处理此响应以删除其缓存的资源副本。

If you decide to use Hash API Method, think of about these situations from day 1. Handling these situations as an afterthought can be expensive.

如果您决定使用哈希API方法,请从第一天开始考虑这些情况。将这些情况作为事后处理可能会很昂贵。

技术3:使用GraphQL来获取所需的内容 (Technique 3: Use GraphQL to fetch just what you need)

GraphQL is a Facebook Open Source project. It started as an idea some years ago but has progressed into a well-defined specification now. There are a handful of libraries for major programming platform that supports GraphQL. As per GraphQL’s website:

GraphQL是一个Facebook开放源项目。 它开始于几年前的一个想法,但现在已经发展成为一个定义明确的规范。 对于支持GraphQL的主要编程平台,有一些库。 根据GraphQL的网站

“GraphQL is a query language for APIs and a runtime for fulfilling those queries with your existing data. GraphQL provides a complete and understandable description of the data in your API, gives clients the power to ask for exactly what they need and nothing more, makes it easier to evolve APIs over time, and enables powerful developer tools.”
“ GraphQL是API的查询语言,是用于使用现有数据执行这些查询的运行时。 GraphQL为您的API中的数据提供了一个完整且易于理解的描述,使客户能够准确地询问他们所需的内容,仅此而已,使随着时间的推移更容易开发API并启用强大的开发人员工具。”

This looks similar to Lazy Get, but in reality, it is even more powerful than that. We will see in a bit how. GraphQL also makes it easy to support Hash API Method without having to add a special endpoint. Before we go into these details, let’s look into a quick example of what GraphQL offers.

这看上去与Lazy Get类似,但实际上,它比Lazy Get更强大。 我们将稍等一下。 GraphQL还可以轻松支持哈希API方法,而无需添加特殊的端点。 在讨论这些细节之前,让我们先看一下GraphQL提供的功能的快速示例。

If an API consumer needs a shallow copy of member resource without any linked resources then it should send the below GraphQL query

如果API使用者需要成员资源的浅表副本而没有任何链接资源,则应发送以下GraphQL查询

Let’s ignore some details like the destination URL for this query and handling of the query on the server. This query returns the specified attributes of the member resource having id 34342.

让我们忽略一些细节,例如此查询的目标URL和服务器上查询的处理。 该查询返回ID为34342的成员资源的指定属性。

If another consumer wants only firstname and lastname then they specify those two attributes in their query. The server will return those attributes. You see how powerful this can be. With Lazy Get, you get all linked resources fully hydrated or none. But it was not possible to strip off some attributes.

如果另一个使用者只需要firstnamelastname那么他们在查询中指定这两个属性。 服务器将返回这些属性。 您会看到它有多强大。 使用Lazy Get,您可以使所有链接的资源完全水分化或完全不水分化。 但是不可能剥离一些属性。

GraphQL’s ability to specify exactly which attributes we want to be returned, lets us support Hash API Method out of the box. A consumer wanting to get the latest value of hash of member resource in the above example would just send the below query

GraphQL能够准确地指定我们要返回的属性,这使我们能够开箱即用地支持Hash API方法。 想要获得上述示例中成员资源哈希值的最新值的消费者将只发送以下查询

Remember, it is still the same API endpoint on the server that is handling these queries. This gives very granular control to the consumers of the API. Consumers can balance between chunky responses and chatty API calls all by themselves.

请记住,处理这些查询的服务器上仍然是同一API端点。 这为API的使用者提供了非常精细的控制。 消费者可以自己在大量响应和聊天API调用之间取得平衡。

One thing worth mentioning is the performance of the Hash API Method using GraphQL. A core premise of Hash API Method is that it needs to return as fast as possible. If we have our own implementation of Hash API Method then we have total control to do any fine tuning we need. With GraphQL, we are limited by what the GraphQL library we use offers. If you use GraphQL version of Hash API Method then make sure it is performance tuned for the use case.

值得一提的是使用GraphQL的哈希API方法的性能 。 哈希API方法的核心前提是它需要尽快返回。 如果我们有自己的Hash API方法实现,则可以完全控制进行所需的任何微调。 使用GraphQL,我们受到所使用的GraphQL库的限制。 如果您使用GraphQL版本的Hash API Method,请确保针对用例对它进行性能调整。

GraphQL就是要控制API的使用者 (GraphQL is all about giving control to the consumers of your API)

I have shown two simple examples of what’s possible with GraphQL. But GraphQL is not limited to simple queries. You can do

我已经展示了GraphQL可能实现的两个简单示例。 但是GraphQL不仅限于简单查询。 你可以做

  1. Specify additional filters on attributes like first 10, last 30 or contains

    在属性上指定其他过滤器,例如前10个,后30个或包含
  2. Specify filters on more than one attribute

    在多个属性上指定过滤器
  3. Group commonly returned attributes in fragments

    将通常返回的属性按片段分组

  4. Query validation

    查询验证

  5. Parameterize queries using variables

    使用变量对查询进行参数化

  6. Dynamically changing query behavior using directives

    使用指令动态更改查询行为

  7. Data mutations after fetch

    提取后的数据突变

An API that fully supports GraphQL, gives its consumer total control over what data they fetch at what point.

完全支持GraphQL的API,使用户可以完全控制他们在什么时候获取哪些数据。

Happy API consumer == Happy API developer == Great API (Happy API consumer == Happy API developer == Great API)

One of the ways of providing good developer experience is to give them some control over the APIs that they interact with. Lazy Get, Hash API Method, and GraphQL provide a mechanism by which API developers can give that control to their consumers.

提供良好的开发人员体验的一种方法是使他们对与其交互的API有所控制。 惰性获取,哈希API方法和GraphQL提供了一种机制,API开发人员可以通过该机制将控制权交给其使用者。

☞ If you like my article, please don’t forget to click ❤ to recommend it to others.

☞如果您喜欢我的文章,请不要忘记单击❤推荐给其他人。

Also, to be notified about my new articles and stories, follow me on Medium and Twitter. You can find me on LinkedIn as well. Cheers!

另外,要了解我的新文章和故事,请在MediumTwitter上关注我。 您也可以在LinkedIn上找到我。 干杯!

Why should you use standard HTTP methods while designing REST APIs?One of the characteristics of a good REST API is that it uses the standard HTTP methods in a way they are supposed to…medium.comVisualising complex APIs using API MapA picture is worth a thousand words…medium.com

为什么在设计REST API时应该使用标准的HTTP方法? 好的REST API的特征之一是,它以应有的方式使用标准的HTTP方法... medium.com 使用API​​ Map可视化复杂的API 一张图片价值一千个单词... medium.com

翻译自: https://www.freecodecamp.org/news/three-ways-to-balance-between-chunkiness-and-chattiness-of-your-rest-api-67e60b7bcca7/

rest api设计

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值