93

RESTfulAPIでページネーションをサポートしたい。

私のAPIメソッドは、を介して製品のJSONリストを返す必要があります/products/index。ただし、潜在的に数千の製品があり、それらをページングしたいので、私のリクエストは次のようになります。

/products/index?page_number=5&page_size=20

しかし、私のJSON応答はどのように見える必要がありますか?APIコンシューマーは通常、応答にページネーションメタデータを期待しますか?それとも、一連の製品だけが必要ですか?なんで?

TwitterのAPIにはメタデータが含まれているようです:https ://dev.twitter.com/docs/api/1/get/lists/members (リクエスト例を参照)。

メタデータの場合:

{
  "page_number": 5,
  "page_size": 20,
  "total_record_count": 521,
  "records": [
    {
      "id": 1,
      "name": "Widget #1"
    },
    {
      "id": 2,
      "name": "Widget #2"
    },
    {
      "id": 3,
      "name": "Widget #3"
    }
  ]
}

製品の配列(メタデータなし):

[
  {
    "id": 1,
    "name": "Widget #1"
  },
  {
    "id": 2,
    "name": "Widget #2"
  },
  {
    "id": 3,
    "name": "Widget #3"
  }
]
4

5 に答える 5

124

ReSTful APIは主に他のシステムによって消費されるため、ページングデータを応答ヘッダーに配置します。ただし、一部のAPIコンシューマーは、応答ヘッダーに直接アクセスできない場合や、API上にUXを構築している場合があるため、JSON応答のメタデータを(オンデマンドで)取得する方法を提供することはプラスです。

実装には、デフォルトとして機械可読メタデータを含め、要求された場合は人間可読メタデータを含める必要があると思います。人間が読めるメタデータは、必要に応じて、またはできれば、またはなどのクエリパラメータを介してオンデマンドで、すべてのリクエストで返すことができinclude=metadataますinclude_metadata=true

あなたの特定のシナリオでは、レコードを持つ各製品のURIを含めます。これにより、APIコンシューマーは個々の製品へのリンクを簡単に作成できます。また、ページング要求の制限に従って、いくつかの合理的な期待値を設定します。ページサイズのデフォルト設定を実装して文書化することは、許容できる方法です。たとえば、GitHubのAPIは、デフォルトのページサイズを最大100の30レコードに設定し、さらにAPIをクエリできる回数のレート制限を設定します。APIにデフォルトのページサイズがある場合、クエリ文字列はページインデックスを指定するだけです。

人間が読める形式のシナリオでは、に移動する/products?page=5&per_page=20&include=metadataと、応答は次のようになります。

{
  "_metadata": 
  {
      "page": 5,
      "per_page": 20,
      "page_count": 20,
      "total_count": 521,
      "Links": [
        {"self": "/products?page=5&per_page=20"},
        {"first": "/products?page=0&per_page=20"},
        {"previous": "/products?page=4&per_page=20"},
        {"next": "/products?page=6&per_page=20"},
        {"last": "/products?page=26&per_page=20"},
      ]
  },
  "records": [
    {
      "id": 1,
      "name": "Widget #1",
      "uri": "/products/1"
    },
    {
      "id": 2,
      "name": "Widget #2",
      "uri": "/products/2"
    },
    {
      "id": 3,
      "name": "Widget #3",
      "uri": "/products/3"
    }
  ]
}

機械可読メタデータの場合、応答にリンクヘッダーを追加します。

Link: </products?page=5&perPage=20>;rel=self,</products?page=0&perPage=20>;rel=first,</products?page=4&perPage=20>;rel=previous,</products?page=6&perPage=20>;rel=next,</products?page=26&perPage=20>;rel=last

(リンクヘッダー値はurlencodedする必要があります)

...そして、total-count選択した場合は、カスタム応答ヘッダーもあります。

total-count: 521

人間中心のメタデータで明らかにされた他のページングデータは、マシン中心のメタデータには不要である可能性があります。リンクヘッダーにより、現在のページとページあたりの数がわかり、配列内のレコード数をすばやく取得できるためです。 。したがって、おそらく合計数のヘッダーのみを作成します。後でいつでも気が変わって、メタデータを追加できます。

余談ですが、私が/indexあなたのURIから削除したことに気付くかもしれません。一般的に受け入れられている規則は、ReSTエンドポイントにコレクションを公開させることです。最後にそれを/index少し濁らせます。

これらは、APIを使用/作成するときに私が持っているのが好きなもののほんの一部です。お役に立てば幸いです。

于 2012-08-29T05:01:46.777 に答える
30

RESTサービスを利用するためにいくつかのライブラリを作成した人として、結果をメタデータでラップすることが方法であると私が考える理由について、クライアントの視点を示しましょう。

  • 合計数がない場合、クライアントは、存在するすべてのものをまだ受信しておらず、結果セットをページングし続ける必要があることをどのように知ることができますか?実行されなかったUIでは、次のページを先読みします。最悪の場合、これは実際にはそれ以上データをフェッチしなかった次/詳細リンクとして表される可能性があります。
  • 応答にメタデータを含めると、クライアントはより少ない状態を追跡できます。応答には要求の状態を再構築するために必要なメタデータ(この場合はデータセットへのカーソル)が含まれているため、REST要求を応答と一致させる必要はありません。
  • 状態が応答の一部である場合、同じデータセットに対して複数のリクエストを同時に実行でき、リクエストをたまたま到着した順序で処理できますが、必ずしもリクエストを行った順序ではありません。

そして提案:Twitter APIのように、page_numberをストレートインデックス/カーソルに置き換える必要があります。その理由は、APIを使用すると、クライアントがリクエストごとにページサイズを設定できるためです。返されるpage_numberは、クライアントがこれまでに要求したページ数ですか、それとも最後に使用されたpage_sizeが指定されたページ数ですか(ほぼ確実に後で、そのようなあいまいさを完全に回避しないのはなぜですか)。

于 2012-08-29T00:13:39.573 に答える
29

同じヘッダーを追加することをお勧めします。resultメタデータをヘッダーに移動すると、dataやなどのエンベロープを取り除くのに役立ち、records応答本文には必要なデータのみが含まれます。ページ付けリンクも生成する場合は、 Linkヘッダーを使用できます。

    HTTP/1.1 200
    Pagination-Count: 100
    Pagination-Page: 5
    Pagination-Limit: 20
    Content-Type: application/json

    [
      {
        "id": 10,
        "name": "shirt",
        "color": "red",
        "price": "$23"
      },
      {
        "id": 11,
        "name": "shirt",
        "color": "blue",
        "price": "$25"
      }
    ]

詳細については、以下を参照してください。

https://github.com/adnan-kamili/rest-api-response-format

Swaggerファイルの場合:

https://github.com/adnan-kamili/swagger-response-template

于 2016-08-02T13:41:20.407 に答える
1

バックエンドAPIの新しいプロパティを応答本文に追加するだけです。例の.netコアから:

[Authorize]
[HttpGet]
public async Task<IActionResult> GetUsers([FromQuery]UserParams userParams)
{
  var users = await _repo.GetUsers(userParams);
  var usersToReturn = _mapper.Map<IEnumerable<UserForListDto>>(users);


  // create new object and add into it total count param etc
  var UsersListResult = new
  {
    usersToReturn,
    currentPage = users.CurrentPage,
    pageSize = users.PageSize,
    totalCount = users.TotalCount,
    totalPages = users.TotalPages
  };

  return Ok(UsersListResult);
}

体の反応ではこのように見えます

{
"usersToReturn": [
    {
        "userId": 1,
        "username": "nancycaldwell@conjurica.com",
        "firstName": "Joann",
        "lastName": "Wilson",
        "city": "Armstrong",
        "phoneNumber": "+1 (893) 515-2172"
    },
    {
        "userId": 2,
        "username": "zelmasheppard@conjurica.com",
        "firstName": "Booth",
        "lastName": "Drake",
        "city": "Franks",
        "phoneNumber": "+1 (800) 493-2168"
    }
],
// metadata to pars in client side
"currentPage": 1,
"pageSize": 2,
"totalCount": 87,
"totalPages": 44

}

于 2020-03-12T19:55:37.590 に答える
-3

一般的に、私は簡単な方法で作成します。たとえば、これらのパラメーターを使用して「localhost / api / method /:lastIdObtained /:countDateToReturn」などのrestAPIエンドポイントを作成します。これは、簡単なリクエストで実行できます。サービスで、例えば。。ネット

jsonData function(lastIdObtained,countDatetoReturn){
'... write your code as you wish..'
and into select query make a filter
select top countDatetoreturn tt.id,tt.desc
 from tbANyThing tt
where id > lastIdObtained
order by id
}

Ionicでは、下から上にスクロールするとゼロ値を渡し、答えを得ると最後に取得したIDの値を設定し、上から下にスライドすると最後に取得した登録IDを渡します

于 2019-07-19T01:19:17.440 に答える