Top / AngularJS / TIPS集 / $resource / パラメタの操作について

さて、AngularJS/TIPS集/$resource にも書いたのですが、$resource を使用するときに使う、

$resource('/api/weather2.json',
  { key: "@key" },    ← コレ
  {
    'get1': {
      method: 'GET',
      params: { id: '@id' } ← コレ
    }
  }
);

について、このパラメタのマッピングがどうもよく分かんなくて「アップするデータのパラメタ名」ぽいのにPOSTでしかつかえない?とか理解が中途半端だったので整理してみました。

http://js.studio-kingdom.com/angularjs/ngresource_service/$resource を引用させていただくと

paramDefaults
URLのパラメータのデフォルトの値を指定します。 これらは、アクションメソッドで上書きする事が可能です。 もし、パラメータのいずれかが関数であれば、 パラメータ値がリクエストの取得を必要とする度に実行されます。 (パラメータが上書きされない限り)パラメータオブジェクトの各キーの値は、最初のURLテンプレートへバインドされ、 もし提供されたキーに余るキーがあれば、URLの検索クエリーとして?の後ろに追加されます。テンプレート/path/:verbと、パラメータ{verb:'greet', salutation:'Hello'}が与えられると、 URLは閣下的に、/path/greet?salutation=Helloになります。もしパラメータの値に接頭辞として@が付いていた場合、 そのパラメータの値は、データオブジェクトから抽出されます。(GETを使用しない操作で便利です。)

ってヤツですね。。。

サンプルとして、以下のサービスをControllerから呼び出すことを考えます。

.factory('sampleService4', function ($resource) {
        return $resource('/api/weather2.json', {},
          {
            'get1'  : {method: 'GET' },
            'post1' : {method: 'POST'}
          }
        );
    }
)
.controller('Menu8Ctrl', function ($scope, sampleService4) {
    var obj = {
        status: "0",
        sessionId: 'abcdefg1',
        address: 'address1',
        apikey: '1234567801',
    }
    sampleService4.get1(obj);
    sampleService4.post1(obj);
})

まずはシンプルな形からやってみます。

シンプルなパタン

上記のままでコントローラから呼んでみると、生成されるRESTリクエストは、以下の通りとなりました。

GET:  http://localhost:9000/api/weather2.json?address=address1&apikey=1234567801&sessionId=abcdefg1&status=0
POST: http://localhost:9000/api/weather2.json
POSTのBody: {"status":"0","sessionId":"abcdefg1","address":"address1","apikey":"1234567801"}

メソッドに渡されたデータが、クエリパラメタとなって渡されたり、POSTするデータとしてBody部にJSONデータが構築されたりしました。 POSTは当たり前な感じですが、GETはJSONデータ(obj)を自動でクエリパラメタにしてくれるあたりがいい感じです。

つぎに$resourceのURLをコロン付きにした場合

$resourceのURLとなるパラメタには下記のようにコロンをつけてプレースホルダを設定することが出来ます。

return $resource('/:status/:sessionId/weather2.json', {}, ...

これがどう置換されるかを見てみました。結果は以下の通り。

GET:  http://localhost:9000/0/abcdefg1/weather2.json?address=address1&apikey=1234567801
POST: http://localhost:9000/weather2.json
POSTのBody: {"status":"0","sessionId":"abcdefg1","address":"address1","apikey":"1234567801"}

GETについては、プレースホルダは、一致するobjのプロパティ値で置換され、その他はクエリパラメタになってうしろにくっつきました。*1 POSTについては、URLは置換されずぺしゃってなり、obj は先ほどと同様、BodyにJSONとして構築されています。

POSTについてはマッピングしないとダメぽい

つぎに@の件です。

'post1': {
  method: 'POST',
  params: {status: "@status", sessionId: "@sessionId"}
}

このように書き換えて実行してみました。 結果は、POSTのURLも正しく置換されました。POSTのBodyも前回同様です。POSTについては、オブジェクトとのマッピングを明示しないとURLを処理しないみたいです。 というかここまで一貫して分かるのは「POSTはURLについては明示的にマッピングしない限り、コロンの置換もクエリパラメタの付与も行わない」ってことでしょうか。

ここまでで分かったこと

$resourceのGETを実行する場合、基本的にURLに載せようとしてくる。URLのコロン付きについては@でマッピングせずとも自動で置換しようとするし、残りはクエリパラメタになる。 $resourceのPOSTを実行する場合、基本的にHTTP Bodyに載せてくるだけでURLは処理しない。URLのコロン付きについては基本的には無視されるため、明示的にマッピングが必要。

さいごゴッテゴテに装飾してみると

最後に、プレースホルダと$resourceのparamDefaultsをつかってゴッテゴテにしてみました。

.factory('sampleService4', function ($resource) {
  return $resource('/api/weather2.json',
    {
      param1: "@status",
      param2: "@sessionId"
    },
    {
      'get1': {
        method: 'GET',
        params: {
          constParam: 'const1',
          param3: '@address'
        }
      },
      'post1': {
        method: 'POST',
        params: {
          constParam: 'const1',
          param3: '@address'
        }
      }
    }
  );
}

こんな事になることはないと思いますが。。以下結果。

GET: http://localhost:9000/api/weather2.json?address=address1&apikey=1234567801&constParam=const1&sessionId=abcdefg1&status=0
POST: http://localhost:9000/api/weather2.json?constParam=const1&param1=0&param2=abcdefg1&param3=address1
{"status":"0","sessionId":"abcdefg1","address":"address1","apikey":"1234567801"}

分かったこと GETに関しては、@を用いたマッピング機構は機能しません。これはPOST時などのBodyのパラメタとの紐付けに使われる機能だからですね。ただ定数値など constParam: 'const1' はちゃんと動きます。 POSTに関しては、まずなにをやってもHTTP Body部が変わることはないようです。さらに@でマッピングされたプロパティをBodyからとりだし、それをparam1,param2,param3などに載せています。もちろんconstParamも動いてます。

ややこしいですが「@機構はGETのときにはつかえない」「POSTはparamsプロパティで明示的に指定しないと、URLを制御することはできず、HTTP Body部のオブジェクトは変更不可」という結論となりました。

コトの発端

そもそもこの機構

'get1': {
  method: 'GET',
  params: {
    constParam: 'const1',
    param3: '@address'
  }
},

について、このparamsの使用目的をユーザ入力値にマッピングしてて、

'get1': {
  method: 'GET',
  params: {
    constParam: 'const1',
    param3: input  <- input はメソッドの引数とか
  }
},

こんな感じに使う想定でした*2が、ココに任意の値が入ってくるように作ると「@」を入れてきたときに 文法エラーとかで落ちちゃうんですよね。 こりゃなんか使い方間違ってるな、、、ってことで調査したのでした。。

結局入力値とかはparamsでやりとりするんでなくて、

sampleService4.get1(obj);

などと引数で渡すのが正しいんでしょうね。。

関連リンク


この記事は

選択肢 投票
おもしろかった 0  
そうでもない 0  

Top / AngularJS / TIPS集 / $resource / パラメタの操作について

現在のアクセス:1029


*1 逆に言うとはじめのパタンはどれもプレースホルダにマッチせず、すべてクエリパラメタにいったケースと考えるべきか
*2 うしろにクエリパラメタに勝手にしてくれるから

トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2016-05-02 (月) 19:02:05 (1316d)