概要
リモートメソッド は、独自のRESTエンドポイントを通じて公開される、モデルのメソッドです。 LoopBackの標準モデルREST APIで提供されていない操作を行うには、リモートメソッドを使います。
Note: リモートメソッドを定義する最も簡単な方法は、コマンドラインでリモートメソッド生成ツールを使うことです。リモートメソッドを定義することの導入的なサンプルは、はじめににあるAPIを拡張する を参照してください。
モデルにリモートメソッドを追加する方法
モデルにリモートメソッドを追加するには、以下のようにします。
- 
    モデル拡張ファイル に関数を作成します。メソッド名によってリモートメソッドが静的メソッドかインスタンスメソッドか決まります。メソッド名が prototype.で始まるものは、インスタンスメソッドになります。さもなくば、静的メソッドになります。注:既定では、リモートメソッドは静的です。インスタンスメソッドを作るには、メソッド名の先頭にprototype.を指定しなければなりません。
- 
    以下の方法のいずれかで、リモートメソッドを登録します。 - モデル定義JSONファイルで、JSONを使って登録する。 詳しくは JSONにリモートメソッドを登録するを参照してください。
- モデル拡張ファイル で、JavaScriptを使って remoteMethod()を呼出して登録する。 詳しくは、リモートメソッドをコードで登録する を参照してください。
 
例
Tip: リモートメソッドのその他の例はAPIを拡張するを参照してください。
Perosonモデルが既に存在し、/greet というエンドポイントを追加して、リクエストで与えられた名前に対して挨拶を返すようにしたいとします。
/common/models/person.jsに以下のようなコードを追加してください。
/common/models/person.js
module.exports = function(Person){
    Person.greet = function(msg, cb) {
      cb(null, 'Greetings... ' + msg);
    }
    Person.remoteMethod('greet', {
          accepts: {arg: 'msg', type: 'string'},
          returns: {arg: 'greeting', type: 'string'}
    });
};
そして、例えば、以下のURLに対して、
POST /api/people/greet
{"msg": "John"} というデータを送信すると、以下のような応答が得られるはずです。
Greetings... John!
Note: 上述のとおり、REST API は”person”の代わりに”people”という複数形を使うように要求します。LoopBackは REST APIルートとしてモデル名の複数形を公開します。
リモートメソッドを登録する
リモートメソッドを登録する方法は2つあります。
- モデル拡張ファイル  (modelName.js) に コードで。
- モデル定義JSONファイル (modelName.json) にJSONで。
コードでリモートメソッドを登録する
LoopBack のモデルはremoteMethod() という、リモートメソッドを登録する静的メソッドを持っています。
Model.remoteMethod(requestHandlerFunctionName, [options])
ここで、
- modelは、リモートメソッドを追加したいモデルオブジェクトです。例えば- Personなどです。
- requestHandlerFunctionNameはリモートメソッドの名前を指定する文字列です。例えば- 'greet'などです。
- optionsは、RESTエンドポイントを設定するパラメータを指定するオブジェクトです。以下の オプション を参照してください。
JSONでリモートメソッドを登録する
モデル定義JSONファイル でリモートメソッドを登録するには、
methods キーの下にメソッド名を追加します。インスタンスメソッドを定義するには、メソッド名の前にprototype.をつけてください。
"methods": {
    "prototype.getProfile": {
      "accepts": [],
      "returns": { "arg": "data", "type": "User", "root": true},
      "http": {"verb": "get", "path": "/profile"},
      "accessScopes": ["read", "read:profile"]
    },
    "someStaticMethod" : { ... }
methodsのは以下にあるそれぞれのキーの値は、以下で説明するオプションオブジェクトです。
オプション
オプション引数は、リモートメソッドがどのように動作するかを定義するJavaScriptオブジェクトです。
  Important:
  All of the options properties are optional. However, if the remote method requires arguments, you must specify accepts; if the remote method returns a value, you must specify returns.
| オプション | 説明 | 例 | 
|---|---|---|
| accepts | リモートメソッドが受け付けて、静的メソッドに渡す引数を定義する。上の例では、関数のシグネチャは Person.greet(name, age, callback)...であるため、 nameが最初の引数、ageが2つ目の引数、そしてコールバックが自動的にLoopBackによって提供される(accepts配列には指定しないこと)。詳細は、引数の説明を参照ください。既定値は空の配列 [ ]です。 | {  ...
accepts: [
 {arg: 'name', type: 'string'},
 {arg: 'age',  type: 'number'},
 ...],
... } | 
| accessScopes | ユーザーは、自身のアクセストークンが `accessScopes` リストで定義されたスコープの内、どれか1つ以上で許可されているときのみ、
        このリモートメソッドを呼び出すことができる。
        認証スコープを参照ください。 既定値は DEFAULTという単一の値を持つリストです。 | accessScopes: [ 'read', 'read:user' ] | 
| description | メソッドを説明する文章。OpenAPI(旧 Swagger)のような APIドキュメント生成ツールによって使われる。 必要に応じて、長い文字列を配列に入れることもできる(以下参照)。 | |
| http | メソッドが公開されるルートを指定する。 下にあるhttp プロパティ を参照ください。 | |
| notes | OpenAPI(旧Swagger)によって使われる追加の注記。 必要に応じて、長い文字列を配列に入れることもできる(以下参照)。 | |
| documented | falseにした場合、このメソッドはOpenAPI(旧Swagger)が生成した文書には登場しなくなる。 | |
| returns | リモートメソッドのコールバック引数を指定する。引数の説明を参照ください。 err引数は暗黙のうちに指定されるので、記述しないこと。
        既定では、空の配列[]です。 | returns: {arg: 'greeting',
          type: 'string'} | 
  Tip: description と notes オプションでは、長い文字列を文字列の配列に分割して、行の長さを制御できます。例えば以下のようにします。
[
 "Lorem ipsum dolor sit amet, consectetur adipiscing elit,",
 "sed do eiusmod tempor incididunt ut labore et dolore",
 "magna aliqua."
]
http プロパティ
http プロパティは、リモートメソッドが公開されるHTTPルートについての情報を提供します。
引数の説明
acceptsと returnsオプションのプロパティは、単一の引数をオブジェクトとして、または順序付けされた引数のセットを配列として定義します。
次の表は、個々の引数のプロパティを示しています。
| プロパティ (キー) | 型 | 説明 | 
|---|---|---|
| arg | String | 引数の名前 | 
| description | String または Array | 引数を説明する文章。OpenAPI(旧Swagger)のようなAPI文書生成ツールによって使われる。 必要に応じて、長い文字列を配列に入れることもできる(上の注記参照)。 | 
| http | オブジェクトまたは関数 | 引数について: HTTPリクエストと引数の値を紐付けを記述する関数またはオブジェクト。下にある入力引数とHTTPのマッピングを参照ください。 | 
| http.target | String | コールバック引数の値と、HTTPレスポンスオブジェクトを紐付ける。以下の値がサポートされている。 
 | 
| required | Boolean | 引数が必須の場合は、true にする。さもなくば false にする。 | 
| root | Boolean | コールバックの引数として: 関数が、単一のコールバック引数を取り、リモートの呼び出し側に返却する大本のオブジェクトとして使いたい場合、
         このプロパティを trueにする。
        さもなくば、大本のオブジェクトはマップ(引数の名前と値)になる。 | 
| type | String | 引数のデータ型。 Loopbackの型のいずれかでなければならない。 加えて、コールバック引数は、特別な型として「file」を指定できる。以下を参照。 | 
| default | String | loopback-explorer の入力フィールドやswaggerの文書を作るために使われる既定値。 注: この値は、引数が存在しない場合は、リモートメソッドに渡されることはない。 | 
| documented | Boolean | falseにすると、このパラメータは OpenAPI(旧Swagger)が生成する文書には登場しなくなる。 | 
例えば、単一の引数はオブジェクトで以下のように指定できる。
{arg: 'myArg', type: 'number'}
複数の引数は、配列で指定する。
[
  {arg: 'arg1', type: 'number', required: true},
  {arg: 'arg2', type: 'array'}
]
ファイル(ストリーム)レスポンスを返す。
コールバック引数として、{ type: 'file', root: true }を指定すると、レスポンスボディを直接送信できる。
ファイル引数は以下のいずれかの値に設定できる。
- String
- Buffer
- ReadableStream (.pipe()メソッドがあるものなら何でも可)
例:
module.exports = function(MyModel) {
  MyModel.download = function(cb) {
    // getTheStreamBody() can be implemented by calling http.request() or fs.readFile() for example
    getTheStreamBody(function(err, stream) {
      if (err) return cb(err);
      // stream can be any of: string, buffer, ReadableStream (e.g. http.IncomingMessage)
      cb(null, stream, 'application/octet-stream');
    });
  };
  MyModel.remoteMethod('download', {
    returns: [
      {arg: 'body', type: 'file', root: true},
      {arg: 'Content-Type', type: 'string', http: { target: 'header' }}
    ]
  });
};
入力引数と HTTP の紐付け
There are two ways to specify HTTP mapping for input parameters (what the method accepts): HTTPと(メソッドが受け付ける)入力パラメータの紐付けを指定する方法が2つあります。
- sourceプロパティを持つオブジェクトを提供する。
- 独自のマッピング関数を指定する。
sourceプロパティを持つオブジェクトを指定する
入力パラメータとHTTPの紐付けに最初の方法を使うには、以下の表に示す値の一つを持つsourceプロパティのあるオブジェクトを提供します。
| source プロパティの値 | 説明 | 
|---|---|
| body | リクエストボディ全体が値として使われます。 | 
| form query path | 値は、ルート引数・リクエストボディ・クエリ文字列を検索する  req.param を使用して参照されます。queryやpathはformの別名ですので注意してください。 | 
| req | ExpressのHTTPリクエストオブジェクト。 | 
| res | ExpressのHTTPレスポンスオブジェクト。 | 
| context | リクエストとレスポンスオブジェクトを保持する、context オブジェクト全体。 | 
例えば、リクエストボディ全体を受け取る引数は以下のように指定します。
{ arg: 'data', type: 'object', http: { source: 'body' } }
ExpressのHTTPリクエストとレスポンスオブジェクトを使用する例は以下のとおりです。
[
 {arg: 'req', type: 'object', 'http': {source: 'req'}},
 {arg: 'res', type: 'object', 'http': {source: 'res'}}
]
独自のマッピング関数を使う
入力パラメータとHTTPの紐付けを指定する2つ目の方法は、独自のマッピング関数を指定するものです。例えば、以下のようにします。
{
  arg: 'custom',
  type: 'number',
  http: function(ctx) {
    // ctx is LoopBack Context object
    // 1\. Get the HTTP request object as provided by Express
    var req = ctx.req;
    // 2\. Get 'a' and 'b' from query string or form data and return their sum.
    return -req.param('a') - req.param('b');
  }
}
マッピングを指定しない場合、LoopBackは値を以下のようにさばきます。(nameは、解決すべき入力パラメータに名前とします)
- HTTPリクエストパラメータ argsがJSONの中にある場合、それは、args['name']として扱います。
- さもなくば、req.param('name')として使います。
JSONフィールドにないデータを返す。
arg プロパティのある return 引数を指定すると、自動的に 同じ名前のフィールドにデータが格納されたJSONオブジェクトを返します。
メインのレスポンスとして、例えば配列のようなデータを返したい場合、 root プロパティを持つオブジェクトを設定し、arg を消去することで可能です。
returns: {type: 'array', root: true}
リモートメソッドルートを指定する
既定では、リモートメソッドは以下のURLで公開されます。
POST http://apiRoot/modelName/methodNameここで、
- apiRoot はアプリケーションのAPI最上位パスです。
- modelName はモデル名の複数形です。
- methodName は関数の名前です。
上の例に従うと、リモートメソッドは以下のように公開されます。
POST /api/people/greet
ルートを変更するには、remoteMethod() に渡すオプションの http.path と http.verb プロパティを使います。例えば以下のようにします。
/common/models/model.js
Person.remoteMethod('greet',{
  accepts: {arg: 'msg', type: 'string'},
  returns: {arg: 'greeting', type: 'string'},
  http: {path: '/sayhi', verb: 'get'}
});
こうすることで、ルートが以下のように変更されます。
GET /api/people/sayhi
すると、 http://localhost:3000/api/people/sayhi?msg=LoopBack%20developer への GETリクエストは、以下のような値を返します。
{"greeting": "Greetings... LoopBack developer"}
リモートメソッドにACLを追加する
独自のリモートメソッドへのアクセスを制限するには、他のAPIへのアクセス制御と同様に、ACL生成ツールを使います。 独自のリモートメソッドをアクセス種別は「Execute」です。
基本的な使い方
たとえば、上の例で使った greet メソッドの呼出しを禁止する場合、以下のようにします。
$ lb acl
[?] Select the model to apply the ACL entry to: Person
[?] Select the ACL scope: A single method
[?] Enter the method name: greet
[?] Select the access type: Execute
[?] Select the role: All users
[?] Select the permission to apply: Explicitly deny access
これで、以下のようなアクセス制御設定が作成されます。
/common/models/person.json
...
"acls": [{
  "principalType": "ROLE",
  "principalId": "$everyone",  // 全員にACLを適用する
  "permission": "DENY",        // メソッド呼び出しを拒否する
  "property": "greet"          // greet() メソッドにアクセス制御を適用する
}],
...
進んだ使い方
他の例として、リモートメソッドの呼出しをモデルの $owner に限定するには以下のようにします。
/common/models/YourModel.js
module.exports = function(YourModel) {
  //...
  YourModel.remoteMethod(
    'someRemoteMethod',
    {
      accepts: [
        {arg: 'id', type: 'number', required: true}
      ],
      // ':id' を RESTのURLに入れることで、 $owner を判断してアクセス制御が行えるようにする
      http: {path: '/:id/some-remote-method', verb: 'get'}
    }
  );
};
リモートメソッドのレスポンスを整形する
起動スクリプトにapp.remotes()が
返すオブジェクトを修正する処理を追加することで、全てのリモートメソッドの戻り値を整形することができます。
/server/boot/hook.js
module.exports = function(app) {
  var remotes = app.remotes();
  // 全ての戻り値を修正する
  remotes.after('**', function (ctx, next) {
    ctx.result = {
      data: ctx.result
    };
    next();
  });
};
リモートメソッドを無効化する
リモートメソッドを無効化するには、Model.disableRemoteMethod(name, isStatic) と Model.disableRemoteMethodByName(name) を使います。詳細は以下を参照してください。