web-dev-qa-db-ja.com

REST APIデザイン:複数のリソースと認証

私は、API呼び出しを外部のプラットフォーム/サービスに転送/統合するサービスに取り組んでいます。

たとえば、ユーザー向けの各サービスでFacebook、Twitter、LinkedIn、Google +のすべての可能なアクション(投稿の作成、投稿の取得、投稿の編集、投稿のリスト)を処理したくないとしましょう。そのため、ユーザー向けサービスはメッセージを使用してこのAPIフォワーダーを呼び出し、何らかの方法で投稿先のサービスを指定し、どのユーザーからのリクエストであるかを指定します。

通話を正常に転送するには、以下を特定する必要があります。

  1. authorizationヘッダーを使用する呼び出しサービス。

  2. 転送先のサービス。

  3. リクエストを開始したユーザー。エンドユーザーの外部サービス資格情報(facebookトークンなど)を呼び出しサービスではなく、転送サービスに保存するべきではありません。

私はこのデータを渡す方法についていくつかのオプションを持っています、そしてどんな入力もいただければ幸いです:

  1. URL /service/{externalServiceName}/user/{userReference}/Object/{objectId}のサブリソースとしてのサービスとユーザーを指定します。 GET /service/facebook/user/uid123/posts/post345これは非常に冗長に感じます。

  2. クエリパラメータを使用します。 /Object/{objectId}?service={externalServiceName}&user={userReference}POST /posts?service=facebook&user=uid123

  3. Authorizationヘッダーを次のようにオーバーロードします:Bearer: <OAuth token>, Service: <serviceName>, User: <userReference>結果としてニースURL(GET/posts /)。 これは完全に仕様から外れているようですが。 仕様には、カンマで区切られたヘッダーに複数の値を指定することが判明しています。

  4. カスタムヘッダーを使用する:X-APIUnify-Service: <serviceName> X-APIUnify-User: <userReference>ここでも、ニースの短いURL(POST /posts/post345)を使用します。

  5. URLでカスタムヘッダーとリソースの組み合わせを使用します:GET Authorization: Bearer: <OAuth token>, User: <userReference> /{externalServiceName}/Object/{objectId}これは私にとって理にかなっています。1。userReferenceはとにかく実際には2番目の承認レイヤーです。 2.サービスは、オブジェクトを所有するリソースです。つまり同じobjectIdは、異なるサービスの異なるリソースを指すことができます。

  6. JWTを使用して、呼び出し側のサービスシークレットで署名されたサービスとユーザーを渡します。 JWT.payload = { "callingServiceId": "5aafcd909c9a25054c3019e3", "externalServiceName: "facebook", "userReference": "uid123", "iat": 1521638763 } Authorization: Bearer: <JWT>

ありがとうございました!

4
Slav

APIの目的から始めて、最高のデザインAPIを検討する必要があります。

APIの目的は次のとおりです。

aPI呼び出しを外部のプラットフォーム/サービスに転送/統合するサービス

したがって、postsエンドポイントから始めます。

POST /posts/

Body
{
    title: "Hello",
    text: "Hello World"
}

ただし、このpostはFacebook、LinkedInなどに投稿でき、ユーザーリファレンスも必要です。

もちろん、この情報を本文で渡すことができます。だが:

  • 同じボディに排他的なプラットフォーム属性を混合します。たとえば、Twitterにはtitleがないか、一部のプラットフォームではtagsをサポートしています。この属性は、それらをサポートしないプラットフォームでは無視されます。 serverは、実行時に彼が受信しているプラ​​ットフォームの種類を把握し、そのプラットフォームに必要なすべてのフィールドがあるかどうかを確認する必要があります。コードは簡単に混乱する可能性があります。
  • クライアントはAPIの複雑さを処理します。一部の属性は一部のプラットフォームで排他的であるため、clientは、sameエンドポイント。
  • このAPIをドキュメント化するのは困難です。その上に Swagger を置くと想像してください。おそらくクライアントは、各プラットフォームでサポートされている情報を理解するのに苦労するでしょう。
  • 新しいプラットフォームのサポートは難しくなります。たぶん、ユーザー参照と一緒に渡される新しい情報を必要とする新しいプラットフォームを追加したいと思うでしょう(私のSlackの例を参照)。
  • プラットフォームごとにバージョン管理を行うことはできません。各プラットフォームを個別にバージョン管理することはできません。これは、各プラットフォームの変更に対応するための素晴らしい機能です。

そして、あなたは、各プラットフォームの多くの可能性と特殊性を考えることができます。

ご覧のとおり、単一のエンドポイントを使用することはリスクがあります

だから私は異なるエンドポイントで分離するのが良いようです:

/platforms/facebook/
/platforms/Twitter/
/platforms/google-plus/

そして、それぞれのURLエンドポイントとbodyには、独自の特徴があります。分割統治。

これは/platforms/{platform}として理解できますが、注意してください。ジェネリックとしてこれを脅威にすると、URLエンドポイントにさらに柔軟性が必要な場合に問題が発生する可能性があります。たとえば、 Slack に投稿を作成するには、プラットフォーム、ユーザー、およびchannelが必要です。

/platforms/slack/users/slav/channels/rest-questions/

このように考えると、プラットフォームを分離して、機能している他のプラットフォームを変更せずに、プラットフォームをそれぞれ変更できます。この場合も、GETおよび別のHTTPメソッドを使用するのが自然です。

冗長性については、APIの使用が明確になれば問題ありません。

1
Dherik