ビジネスレイヤーに次のインターフェイスがあります
public interface IUserService
{
void CreateUser(User user);
List<User> FindUsersByName(string searchedString);
User GetUserById(int userId);
User GetUserByCredentials(string login, string password);
void UpdateUser(User user);
void UpdateUserPassword(int userId, string oldPassword, string newPassword);
}
次に、このインターフェースにWeb APIを提供したいと思います。このインターフェースには、1つのアイテムget
とGetUserById
を返すGetUserByCredentials
メソッドが複数あることがわかります。また、複数の更新メソッドUpdateUser
とUpdateUserPassword
、将来的には、たとえばGetAllUsers
などのコレクションを返すgetメソッドを追加したいと思うかもしれません。
明白な解決策は、この機能を1つのコントローラーにカプセル化することでした。だから私が最初にやったことは、WebApiConfig
でルート設定を
config.Routes.MapHttpRoute(
name: "DefaultApi",
//as you can see I added {action} to the path so that, it will be possible to differentiate between different get/put requests
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
次に、このようなUsersController
を作成しました
public class UsersController : ApiController
{
private readonly IUserService _userService;
public UsersController(IUserService userService)
{
_userService = userService;
}
// POST api/users/createuser
[HttpPost]
public IHttpActionResult CreateUser(User user)
{
//some code
}
// GET api/users/getuserbyid?id=1
[HttpGet]
public IHttpActionResult GetUserById(int id)
{
//some code
}
// GET api/users/getuserbycredentials?login=log&password=pass
[HttpGet]
public IHttpActionResult GetUserByCredentials(string login, string password)
{
//some code
}
// GET api/users/findusersbyname?searchedString=jack
[HttpGet]
public IHttpActionResult FindUsersByName(string searchedString)
{
//some code
}
// PUT api/users/updateuser
[HttpPut]
public IHttpActionResult UpdateUser(UserBase user)
{
//some code
}
// PUT api/users/updateuserpassword?userId=1&oldPassword=123&newPassword=1234
[HttpPut]
public IHttpActionResult UpdateUserPassword(int userId, string oldPassword, string newPassword)
{
//some code
}
}
上記のコードからわかるように、たとえばGetUserById
-api/users/getuserbyid?id=1
、GetUserByCredentials
-api/users/getuserbycredentials?login=log&password=pass
など、アクションメソッドごとに異なるURIがあります。このソリューションはこれまでのところ正常に機能しますが、RESTに従って複数のgetを使用できないことがわかっている限り、このソリューションはRESTfulサービスの制約に引き続き準拠していますか?そうでない場合、どうすれば本当にRESTfulにできますか?このインターフェイスを別のコントローラーに分割するという考えは、私には少し奇妙に思えます。将来的には、GetUsersByGender
、GetUsersByDateOfBirthday
などの新しいメソッドをインターフェイスに追加する可能性があるためです。 (毎回新しいコントローラーを作成する場合、それは私には正しく聞こえません)
RESTに従って複数の取得を行うことはできません
あんまり。 [〜#〜] rest [〜#〜] とAPIモデリングは異なるテーマです。 REST APIは、Fieldingが彼の導入した前提に基づいた統合戦略であることを意図しています 論文 分散型建築スタイルについて。これらの前提は、APIとは何の関係もありませんモデル化され、提供されるリソース、URI、およびセマンティクスの数。
例えば:
/api/users-living-in-courscant
/api/users-not-living-in-courscant
/api/users?q=living:coruscant
/api/users?q=id:12345
/api/user/12345
/api/me
上記のURIの一部は同じリソースを参照する場合があり、主な違い(および重要な点)はそれぞれのセマンティクスにあります。
それで、このソリューションはRESTfulサービスの制約にまだ準拠していますか?
私の意見では、あなたのアプローチはAPI RESTよりもRPCのようなWebサービスに近いと思います。 Richardson Maturity Model に関するMartin Fowlerの記事をご覧ください。
Martinの投稿を注意深く読むと、MartinがAPIモデリング手法やベストプラクティスを紹介していないことがわかります。彼はHTTPセマンティクスに従って通信クライアント/サーバーを適切に作成する方法に焦点を合わせています。リソースを表現して発見する方法。
ただし、これらのリソースを識別する方法については触れていません。 URIの形成方法については触れていません。
そうでない場合、どうすれば本当にRESTfulにできますか?
APIを完全にRESTfulにすることが懸念される場合は、まずFieldingの論文を読むことをお勧めします。 RESTの意味を理解したら、APIモデリングに関連するドキュメントを探します。最後が前者に同意したらすぐに、あなたは良い道にいるはずです。
作業を開始するための2つのリンク:
上記のリンクは、慎重な順序に従っています。基本から高度な概念に至るのは自然な流れだと思います。ゼロから。
私は言葉の慣習を意図的に強調しました。これらは、ニーズに合わないと見なされた場合、却下または解釈できます。
このトピックに興味がある場合は、次の本が参考になります。
API設計ルールブック :主にAPIモデリングに焦点を当てています。 WebアーキテクチャとREST原則の概要を簡単に紹介します。
実際の休憩 :これはもっと高度なものだと思います。むしろ、APIモデリングよりも統合としてRESTの利点に焦点を当てました。
RESTはメソッドの数を制限しません。必要な数だけ使用できます。 APIと実装は2つの異なるものです。 APIがRESTアーキテクチャーに準拠するようにしたい場合は、リソースを交換することです。コードでの処理方法は自由です。
コードはユーザーを扱います。しかし、URIはリソースではなくアクションのように見えます。次のようなスキーマについて考えてみます。
GET /users - returns the collection of users
GET /users/{id} - return the user with a specific ID
POST /users - add a user to the collection
searching based on criteria could look like this:
GET /users?country={country-code}&city={city}
これにより、ユーザーにリソースが公開され、HTTPプロトコルのメソッドを使用して、これらのリソースに対して実行するアクションが識別されます。
APIが何であるかについて人々はさまざまな考えを持っていますREST API。私が読んだり、例で見たりしたAPIのほとんどは制限されています。それらは多数のWebスケールで公開されていませんクライアントの実装。
また、転送されたリソースを識別するための明示的なMIMEタイプの使用や、リソース間のリンクを定義するための構造化された方法は、しばしば含まれていません。
したがって、APIをどのようにしたいか、「本当の」REST API、または論理URI、HTTPメソッド、HTTP応答コードを使用して通信する単純なものを考えてください。
私が知る限り、RESTに従って複数の取得を行うことはできません
いいえ、そうではありません。持てないのは状態です。たとえば、次のようなAPIがあるとします。
POST /set-current-user/[id]
GET /user-info
GET /user-avatar
POST /change-password
つまり、ユーザーのプロフィール写真を取得するには、最初にset-current-user
を呼び出す必要があります。RESTfulではありません。
それとは別に、 6つのアーキテクチャ上の制約 の中には、複数のアクションを持たないように指示する制約がないため、コントローラで必要なだけGETまたはGET以外のアクションを自由に使用できます。コントローラごと。
また、私はあなたの例の1つを強調表示することを避けられません:
GET api/users/getuserbycredentials?login=log&password=pass
これが実際に使用したルートである場合は、使用しないでください。 HTTPSを使用していても(ここでは機密のユーザーデータを操作しているので、HTTPSを使用するしている)、これには、パスワードをプレーンに送信するという大きなセキュリティ上の欠陥がありますサーバーのログに直接テキスト。ログが暗号化されていて、アプリケーションサーバーからログへのトラフィックが安全なプロトコルで行われていると確信している場合でも、ユーザーのパスワードをプレーンテキストで保存するという唯一の事実は、セキュリティの面でひどいものです。それをしないでください。決して。