web-dev-qa-db-ja.com

RESTより大きい、より小さい操作のURL設計

ある種類の操作としてページ付けに基づく顧客の要求を処理したり、別の種類の操作として演算子よりも大きいまたは小さい要求を要求したりできる残りのサービスのURLを設計するのは少し難しいです。例えば:

ページネーション:

GET /customers/0/100

これにより、ページ0で100人の顧客が取得されます。

より大きい/より小さい:

また、nより大きいIDを持つ顧客を取得するためのURL設計も必要です(たとえば、716としましょう)。どのようにURLに「より大きい」または「より小さい」を組み込みますか。 ">"と "<"はURLでは違法であることを覚えておく必要があります。このURLのデザインは奇妙に見えます:

GET /customers/greaterthan/716
GET /customers/lessthan/716

上記で指定されたページ分割パターンと競合する範囲を使用することはできず、どのような場合でも適切な解決策ではありません。例:

GET /customers/716/999999999999
GET /customers/0/716

私は明白な何かを見逃していると確信しています-誰かがより良い解決策を持っていますか?

30
Vidar

Paginationgreaterthanおよびlessthan 、クエリパラメータのように聞こえます。これらのパラメータを使用してリソースをクエリしているからです。だからあなたは次のようなことをするべきです:

/ customers?page = 1、または
/ customers?page = 1&gt = 716、または
/ customers?page = 1&gt = 716&lt = 819

ページのサイズを制限することもできます。

/ customers?page = 1&gt = 716&lt = 819&maxpagesize = 1

ここで、gtは(xml-escapingと同じ)およびltは「より小さい」を表します。

32
Tarlog

複数のパラメーターがあり、各パラメーターにいくつかの条件を適用する必要がある場合は、JSONオブジェクトをパラメーターに渡すことをお勧めします。

idpageの条件を実行するとします。

/customers?id={"lt": 100, "gt": 30}&page={"start": 1, "size": 10}

Id(s)less than100およびgreater than30のページ1およびページ番号10 。

したがって、他のパラメータに別の条件を適用したい場合は、次のようにして実行できます。

/customers?id={"lt": 100, "gt": 30}&children={"lt": 5, "gt": 2}&page={"start": 1, "size": 10}

このクエリは、Id(s)less than100およびgreater than30、子より小5およびより大2 ページ番号1、ページサイズ10。

RESTful APIの設計に関するこのドキュメントを読むことを強くお勧めします: http://blog.luisrei.com/articles/rest.html

16

RESTは、HTTPに固有であると見なすべきではないアーキテクチャスタイルです。 URIのパターンは、アーキテクチャーをRESTfulにするものではありません。

そうは言っても、おそらくこれらのクエリが文字列の最後にクエリパラメータとして来るようにURIを作成したいと思うでしょう。

/customers?min=0&max=76
7
pc1oad1etter

@ジュリオ・ファーマン:

まあ、問題は複数のパラメーターを取得したときに始まります。 「18歳以上60歳未満の子供が2人以上いる顧客」のクエリ文字列を想像してみてください。

次のように、任意のクエリパラメータを定義できます。

/customers?min-age=19&max-age=59&min-children=3

私の例では、minとmaxは整数であり、包括的です。必要に応じて変更できます。 URIに含まれるものはすべて、リソース識別子の一部を意味します。私の個人的な見解では、?の後の部分は、SQLクエリのWHERE部分の句に相当します(ここには表示されていないORDER BYおよびLIMIT)。

SELECT * FROM customers WHERE age>=19 AND age<=59 AND children>=3

編集:
min-およびmax-接頭辞の代わりに、><(およびおそらく!)をパラメーターの最後の文字として許可できます名前なので、min-ageの代わりにage>というパラメーターがあり、クエリ文字列の値と組み合わせると、最終的にage>=19のようになります:-)
明らかに、このトリックは、比較に等号が含まれている場合にのみ使用できます。

7
Nicholas Shanks

サーバーログを取得するとし、データが次のようになっているとします。

{
    "protocol": "http",
    "Host": "example.domain.com",
    "path": "/apis/classified/server/logs",
    "method": "GET",
    "ip": "::ffff:127.0.0.1",
    "time": 1483066346338,
    "usingTime": 12,
    "status": 200,
    "headers": {
        "user-agent": "Mozilla/5.0 Chrome"
    }
}

そして、あなたはこのようにクエリしたいのですが、

  • protocol'http'と等しい。
  • Host'example.domain.com'と等しい、または'example.domain.me'と等しくない。
  • path'/apis/classified/server/logs'と等しい、または/*classified\/server*/が好きです。
  • method'DELETE'と等しい、または'GET'と等しくない、または['POST', 'PUT', 'DELETE']内。
  • ip'127.0.0.1'と等しい、または'127.0.0.1'と等しくない。
  • usingTime3500より大きいか、1500以上で3500以下です。
  • status404と等しいか、200と等しくないか、400以上で500未満です。
  • headers.user-agent/*chrome*/iが好きです。

ここでは、ルートは次のようになります。

  • /apis/classified/server/logs?path=/apis/classfied
  • /apis/classified/server/logs?path.regex=*classfied*
  • /apis/classified/server/logs?method.ne=GET
  • /apis/classified/server/logs?method=POST&method=PATCH&method=PUT
  • /apis/classified/server/logs?usingTime.gte=1500&usingTime.lte=2500
  • /apis/classified/server/logs?headers.user-agent.regex=*chrome*

サーバーとしてexpress.jsを使用している場合、req.queryは次のように構成されます。

  • {"path": "/apis/classfied"}
  • {"path": {"regex": "*classfied*"}}
  • {"method": "DELETE"}
  • {"method": ["GET","POST","PUT"]}
  • {"usingTime": {"gte": "1500","lte": "2500"}}(lte:より小さいか等しい)
  • {"status": {"ne": "200"}}}(ne:等しくない)
  • {"path": {"regex": "*classfied*"}}
  • {"headers": {"user-agent": {"regex": "*chrome*", "flag": "i"}}}

そして、たくさんのif-elseを使用して、マングースクエリメソッド、またはSQL文字列を構成します。

2
Fisher

ここに私がそれをしている方法があります。

たとえば、数値であるフィールドageがあるとします。

これはURLがどのようになるかです
等しい:/ filter/age = 5
より大きい:/ filter/age [gt] = 5
以上:/ filter/age [gte] = 5
未満:/ filter/age [lt] = 5
以下である:/ filter/age [lte] = 5
等しくない:/ filter/age [ne] = 5

次に、これらの引数をバックエンドに渡すと、キーを解析して、年齢に基づいて正しいフィルターに変換するスクリプトがあります[INSERT_OPERATOR_HERE]

1
Hackbyrd

私はそれを範囲として実装し、どちらかが開いている場合は、埋めないでください。

GET /customers/16-
GET /customers/-716

すべての顧客を要求する場合、すべてを追加するのではなく、空のままにしてください

GET /customers

または、必要な場合-番号/コードにサインインし、次のように使用します。

GET /customers/16/
GET /customers//716
GET /customers/16/716

スラッシュが数字の一部である場合は、スラッシュをエスケープできます。

1
RobAu

警告:以下の免責事項をお読みください

この質問がC#に関連しているかどうかはわかりません。しかし、サーバー側でクエリにlinqを使用している場合は、別の提案があります。

GET /customers?filter=CustomerNo>=16 AND CustomerNo<=716

次に、サーバー側で:

using System.Linq.Dynamic;

var filteredCustomers = myCustomerTable.Where(filter);

これは、すべての中で最も柔軟なソリューションになるはずだと思います。


2017年1月19日に警告が追加されましたDynamic Linqにコードインジェクションエクスプロイトが存在することが気付きました。上記の例では、クライアントがサーバーでコード実行を開始できる可能性が開かれています。

0
user3414239

一部のRESTベースの標準は、この問題への適切なアプローチを提供します。例: https://www.hl7.org/fhir/stu3/search.html

あなたの問題はそのように解決できます:GET /customers?id=ge500&id=lt1000

また、業界レベルの標準よりはるかに相互運用性の高い OData もあります。そして、それはこのスタイルを提案します:GET /customers?$filter=id ge 500 and id lt 1000

0
astef