天天看點

rest api設計_在設計REST API時如何平衡粗俗與閑談 在設計REST API時如何平衡粗俗與閑談 (How to balance chunkiness against chattiness when designing your 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.

為簡便起見,以上代碼未完整顯示

memberships

rsvps

friends

資源。 實際上,這些資源将具有比我在此處顯示的資源更多的屬性。 他們甚至可以擁有自己的連結資源。

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?

很好 現在,使用者可以控制什麼資料伺服器傳回。 但是其他資源(

rsvps

friends

怎樣? 伺服器隻是要将它們從響應中排除嗎? 如果伺服器将它們排除在外,那麼消費者在需要它們時如何獲得這些資源?

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.

這樣,如果使用者決定擷取

rsvps

friends

資源,則他們要做的就是在相應的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.

您可以使用Siren , HAL或Collection + 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.

如果另一個使用者隻需要

firstname

lastname

那麼他們在查詢中指定這兩個屬性。 伺服器将傳回這些屬性。 您會看到它有多強大。 使用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!

另外,要了解我的新文章和故事,請在Medium和Twitter上關注我。 您也可以在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設計