パラメータとクエリ文字列の使用に関するREST API設計の最適プラクティス

APIについては、どこにパラメータを入力するか?REST APIでのパラメータとクエリ文字列の使用に関する最適プラクティス

API設計の際のゴールは、ユーザーに提供されるサービスに対し、ある程度のパワーを込めることです。HTTP動詞とリソースURLが基本的な相互作用を及ぼす一方、しばしば追加機能の提供が重要な場合があります。さもないと、システムは作業するには扱い難くなってしまいます。

その一例がページネーションです。データベースに何百万もあれば、ひとつひとつを一回の応答で全てクライアントに送信することなど出来ません。

これを成し遂げる方法にパラメータ化があります。

パラメータ化とは?

一般的に言えば、パラメータ化とはリクエストに対してのある種の設定です。

プログラミング言語では、関数から戻り値を求めることが出来ますが、その関数がパラメータを受け入れない場合、この戻り値に直接作用させることは出来ません。

以下のRoy Fieldingからの引用にも示すように、API、特にREST APIのような処理状態を把握しないAPIについても同様のことが起こります。

REST相互作用の全ては処理状態が把握されません。つまり、各要求には、それに先行し得る要求とは別に、コネクターの要求理解に必要な全情報が含まれています。

HTTPには要求にパラメータを追加する多くの方法があります。クエリ文字列、 POST、PUT、PATCHリクエスト、およびそのヘッダなどがそれに該当します。それぞれに独自のユースケースとルールがあります。

故にパラメータをどこに入力するかを決める前に考える必要があり、そしていかに適切な場所に入力するかをチェックしなければなりません。

制約を極力少なくして全データを取り込む最も簡単な方法は、全データを本体に取り入れることです。 弊社自身もそのように機能した多くのAPIを見て来ました。 全終了点でPOSTを使用すれば全パラメータは本体に入ります。特に何十年にも渡り成長し、ますます多くのパラメータを蓄積したレガシーAPIに対しては、このような処置を施さなければなりません。大量のデータはクエリ文字列に収まり切れません。

たいていの場合はこうしたケースですが、API設計におけるエッジケースに思いを巡らしてみたいと思います。前もって正しい質問をすれば、早めにそのような結果に至らず防ぐことも出来ます。

どのようなパラメータを追加すべきか?

最初に自身に問う質問は、どのようなパラメータを追加すべきか?だ。

恐らくそれはHTTP仕様で既に標準化されているヘッダフィールドのパラメータです。

多くの標準化された分野があり、時には他所でこの情報を加えることにより、わざわざ一からやり直す事ともなります。難しく捉えようと言うのではありません。例えば、GraphQLは、RESTの観点から見ればクレージーにも思えましたが、それでも機能します。しかし、既存のものを使用すればより簡単に済む場合もあります。

例えば、レスポンスが持っているフォーマットやメディアタイプの定義を可能にするAcceptヘッダがあります。これを使用してJSONやXMLが必要であることをAPIに伝えることが出来ます。これを使用すれば、バージョンやAPIのレスポンスを確認する事も可能です。

キャッシュバスターである文字列を使用する代わりに、APIがキャッシュ無しの動的レスポンスを送ることを防ぐ為に使用するキャッシュ制御ヘッダもあります(?cb = <RANDOM_STRING>)。

APIの承認の詳細によっては承認されたデータと承認されていないデータを要求するとサーバーからの応答が異なる可能性があるため、承認もパラメータと見なされる可能性もあります。この目的が故に、HTTPは承認ヘッダを定義します。

全デフォルトヘッダフィールドをチェックした後の次のステップは、パラメータ用のカスタムヘッダフィールドを作成するか、それをURLのクエリ文字列に入力するかの判断となります。

クエリ文字列はいつ使用すべきか?

追加したいパラメータがデフォルトのヘッダフィールドに属さず、機密でもないことが分かっていれば、クエリ文字列が適切な場所に入力されているかどうかが確認出来ます。

名前が示すように、歴史的に言えばクエリ文字列の使用はデータを問い質すことでした。サーバーにいくつかのキーワードを送信するために使用される<isindex> HTML要素があり、サーバーはそのキーワードに何らかの形で一致するページリストで応答します。

後にクエリ文字列は、ウェブフォームがGET要求を通じてデータをサーバーに送信するために再利用されるようになりました。

故にクエリ文字列使用に適した主たるユースケースとは、フィルタリングと、検索とページネーションという2つの特別なフィルタリングとなります。既にこの記事で取り上げられているので、ここで更なる詳述は控えます。

しかしウェブフォーム目的への再利用が示すように、様々な種類のパラメータにも使用可能です。RESTful APIは、本体でPOSTまたはPUTリクエストを使用してフォームデータをサーバーに送信します。因ってこれはユースケースでは無いものの、それでも他のパラメータの介在が可能です。

一例はネスト化した表現へのパラメータです。 デフォルトにより記事を平易な表現で返し、?withCommentsのクエリ文字列が終点に追加された場合、その記事のコメントはインラインで返される事となるので、1つの要求だけが必要となります。

そのようなパラメータはカスタムヘッダに入るか、或いはクエリ文字列は殆どの場合、開発者の経験に依存する事となります。

HTTPの仕様では、ヘッダフィールドは関数パラメータに似ているとも言われ、実際に使用したいパラメータとして考えられてはいますが、URLにクエリ文字列を追加することはすぐに可能であり、その為に顧客ヘッダを作成する事よりはもっと解り易いです。

こうしたフィールドは、プログラミング言語のメソッド呼び出しでのパラメータとは変形として同等の意味を成し、要求修飾子として機能します。

全終点で変わらないパラメータは、ヘッダに適合します。例えば、認証トークンはあらゆるリクエストに応じて送信されます。

非常に動的なパラメータ、特に少数または1つの終点に対してのみ有効なパラメータは、クエリ文字列に含める必要があります。例えば、フィルタパラメータは終点ごとに異なります。

ボーナス:配列とマップパラメータ

クエリ文字列内の配列パラメータについてはどうするか?これはかなり頻繁に生じる問題の1つでした。

例えば、検索したい複数の名前がある場合など。

解決策の1つは角括弧を利用することです。

/authors?name[]=kay&name[]=xing

しかしHTTP仕様はこう述べています。 

インターネットプロトコルのリテラルアドレス、バージョン6 [RFC3513]以降で識別されるホストは、IPリテラルを角括弧( "["と "]")で囲むことによって区別される。これが、URI構文で角括弧文字使用が許される唯一の場所だ。

HTTPサーバーと多くのクライアントはこの事実を気にはしていません。しかし、覚えておくべきでしょう。

お勧めの他の解決策には、単純に1つのパラメータ名を複数回使用することがあります。

/authors?name = kay&name = xing

これは有効な解決策ではあるが、開発者の経験則を衰えさせる事につながる可能性もあります。多くの場合、クライアントはURLに追加される前に単純な文字列変換を経たマップのようなデータ構造を使用するだけですが、これは以下に続く値をオーバーライドしてしまう可能性もあります。要求を送る前により複雑な変換が必要となります。

もう1つの方法は値を - 文字で区切ることです。URL内コード化されていなくても構いません。

/authors?name=kay,xing

地図のようなデータ構造に- 文字をコード化せずに使用する事も出来ます。

/articles?age.gt=21&age.lt=40

クエリ文字列全体をURLエンコードすることも可能であり、必要とする文字やフォーマットに使用する事も出来ます。こうする事で開発者の経験則をかなり減少させてしまう可能性もあることは覚えておいて戴きたい事です。

クエリ文字を使用しない時とは?

クエリ文字はURLの一部であり、クライアントとAPI間にいる全ての人がURLを読み取れます。因って、パスワードなどの機密データはクエリ文字に含めるべきではありません。

また、URL設計とその長さを真剣に考えない限り開発者の経験則は大きく損なわれます。確かに殆どのHTTPクライアントはURLに5桁の長さの文字を入れる事も出来ますが、斯様な種の文字列をデバッグすることはあまり好ましとは言えません。

如何なるものもリソースとして定義出来ます。故に時にはPOST終点を利用し、パラメータを多用する事も理には適ってはいます。こうして本体内の全データはAPIに送られます。

それはどうしてもデバッグ出来ないような長いクエリ文字列で多くのパラメータを送るリソースにGETリクエストを送信する代わりに、例えば検索リソースなどのリソースの作成として設計する事も出来ます。APIが要求を満たすための要件に応じて、これを使用し計算結果をキャッシュすることも可能です。

/search 終点に新たなリクエストをポストします。こうして本体の検索設定/パラメータを保持し、後に検索結果取得に使用可能な検索IDを取得します。

結論

全最適プラクティスと同様、APIデザイナーまたは設計者としての我々の仕事は、「ベストソリューション」としての1つのアプローチをフォローするのでは無く、いかに我々のAPIが使用されているかを知ることです。

容易に成就するユースケースが最も頻繁に使用されるべきであり、悪しき事になる事が本当に困難となるべきです。

故にAPIの使用パターンを当初から分析する事が常に重要です。データの入手が早ければ早いほど、設計が混乱した場合、速やかな変更の実行が可能となります。Moesifの分析サービスはそれを支援します。

Moesifは、2000を超える組織体で顧客の利用パターン計測に使用されている最先端のPI分析サービスです。

直進すれば把握するにも実行するにも簡単ではありますが、我々はそこから得られるものを見なければなりません。

ネスト化されたリソースによりURLはより読みやすくなりますが、それが過ぎると逆に長すぎて読みづらくなります。パラメータも同様です。 膨大なクエリ文字列に至る1つの終了点を自ら作成していると気づいたならば、そこから別のリソースを抽出し、パラメータは本体内に送った方が良いでしょう。

この記事は、著者の許可を得て翻訳しています。なお、原文はこちらです。

新着ピック  






















新着ニュース

5月のDeepRacerのF1 ProAm Event のタイムトライアルで3位になったので、EC2でのDeepRacerのローカルトレーニング 2020 環境構築手順を共有します | Developers.IO

5月のDeepRacerのF1 ProAm Event...

DevelopersIO / 1時間前


ベイエリアの黒人テックリーダーが人種差別的不公正に向けた行動を呼び掛け | TechCrunch Japan

英国チャレンジャーバンクのMonzoが最大120名を解雇へ、「経済状況」は未だに困難 | TechCrunch Japan

[アップデート]  S3 アクションの最終実行履歴が IAM からカンタンに確認できるようになりました | Developers.IO

“敏感な”ロボットフィンガー、コロンビア大が開発

電子の姿、AIで予測 数時間かかっていた計算を数秒で 東大と産総研

ツイキャス運営のモイ、音声SNS「パルミン」公開 2Dアバター同士で通話

楽天モバイルに聞く「Rakuten Mini」開発秘話 なぜ自社ブランド端末が必要だったのか

[Amazon SageMaker] イメージ分類のモデルをNeoで最適化して、RasPi4+OpenCV+Webカメラで使用してみました | Developers.IO

Snapchatがトランプ大統領の投稿をDiscoverタブに掲載しないと発表 | TechCrunch Japan

GitHubで複数種類のCI/CDサービスと連携したRepositoryの必須ステータスチェックの動作を確認してみた | Developers.IO

ブロックチェーンを活用して複数デバイスでシームレスな個人情報管理を実現するMagicとは? | TechCrunch Japan

SpaceXがStarlink衛星60基を追加打ち上げ、1基に衛星の太陽光反射を防ぐサンバイザーを搭載 | TechCrunch Japan

畜糞を1週間で肥料化する昆虫テックのムスカがECサイト開設、代表取締役2名の新体制に | TechCrunch Japan

ZoomのQ1売上は前年同期169%の360億円、無料ユーザーのコスト増で売上総利益率は大幅低下 | TechCrunch Japan

Apple、6月5日にApple Watchで「環境の日チャレンジ」

AIがカメラ映像から密集度と群衆人数をリアルタイム解析、Elixが新型コロナ対策として開発 | TechCrunch Japan

Google Nest Hubシリーズでのオンライン帰省は現実的か、試してみた

au PAYに統合された「Ponta」を使ってみた Apple Payなら還元率と利便性が向上

Apple Cardが米薬局大手Walgreensと提携し50ドルの新規登録ボーナスを提供 | TechCrunch Japan

もっと見る
会員登録
Register
記事をPICKする

会員登録すると、もっと便利に利用できます。