ShinobiLayer: SoftLayer API 次の一歩: methodの実行方法と返り値の制御(1)

#はじめに
「データ型オブジェクト編」では、SoftLayer APIの利用方法として、データ型オブジェクトについて記事を書きました。maskを使って、local propertyだけでなく、relational propertyを取得する方法が分かったので、情報を取得するだけならgetObject()だけでも対応可能じゃないか？、という方もいらっしゃるかもしれません。
とはいえ、やっぱりmethodを使いこなさないと困るケースは少なからず存在します。たとえば、getXXX()ではなく、updateXXX()のような更新系作業は、methodを使わざるを得ないでしょう。また、ticketやアクセスログのような大量データを収集する際には、やはりAPI呼び出し時にある程度のフィルタリングを実施しておく方が望ましいでしょう。というので、やっぱりmethodの習得は避けては通れないところです。
今回は、

* method呼び出し時にオブジェクトIDが必要なケースの見分け方
* パラメーター、オブジェクトID、mask値の指定の順番
* limit/offset/filter

などを紹介したいと思います。

#前提

* 使用言語: Python（SoftLayerでのスタンダード。slコマンドもPythonを使って実装されています）
* slコマンドのsetupが既に完了していること。以下の記事などによくまとめられています。
 - http://niccloud.niandc.ne.jp/?p=892
 - http://www.creationline.com/lab/3893
* 前回の資料（データ型オブジェクト編）が理解できていることが望ましい。正直こっちの方が重要なので。
 - http://qiita.com/testnin2/items/f04ca0cee9b2f0a8f830
 - http://qiita.com/testnin2/items/6be9b87571a99e01002a
 - http://qiita.com/testnin2/items/80b7808b1a69babcde65

#データ型オブジェクト編の復習

簡単に最初の2つのルールだけを列挙しておきます。

* **「ルール1：`client['Service名']`で、Serviceオブジェクトを呼び出す。ただし、`client['SoftLayer_Account']`と書いても良いし、`client['Account']`のように"SoftLayer_"の部分を省略しても良い。」**
* **「ルール2: `client['Service名'].method`は、Serviceオブジェクトを返さない。返すのはリテラル(stringやbooleanなど）、データ型オブジェクト、データ型オブジェクトの配列である。」**

SoftLayerのAPI ReferenceにおけるAccountのServiceとData Typeを、念のため記載しておきます。
http://sldn.softlayer.com/reference/services/SoftLayer_Account
http://sldn.softlayer.com/reference/datatypes/SoftLayer_Account



#methodが実行できない！？
ユーザーデータを取得したいので、API Referenceを検索してみます。API Referenceにおいて、右上のチェックボックスで検索が可能です。

<検索条件を入れる>
![search_username.jpg](https://qiita-image-store.s3.amazonaws.com/0/62127/a2ef76ed-b6ff-6705-4e6f-a0a4e5c89025.jpeg)

<検索結果>
![search_result_username.jpg](https://qiita-image-store.s3.amazonaws.com/0/62127/17bf7dea-cd9e-628a-ffec-2ec974eee300.jpeg)


検索結果によると、SoftLayer_User_Customerデータオブジェクトが該当しそうだと想像されます。実際、API Referenceを見てみると、確かにユーザーに関する情報が含まれていることが確認できます。幸い、SoftLayer_User_Customerには、getObject()というmethodも存在するようです。
http://sldn.softlayer.com/reference/services/SoftLayer_User_Customer/getObject

となると、ルール1に従って、

```py:step1_ng.py
import SoftLayer
import pprint
pp = pprint.PrettyPrinter(indent=4)
client = SoftLayer.create_client_from_env()
user = client['User_Customer'].getObject()
pp.pprint(user)
```
と書けば良さそうですが、これはエラーになってしまいます（*私はSoftLayerのAPIのコードを書き始めたときに、同様のエラーに遭遇して理由も分からずげんなりしたものです・・・*）。よくよく見ると、「Object does not exist to execute method on. (SoftLayer_User_Customer::getObject)」と、該当オブジェクトが存在しないというエラーが出ています。これはどういうことなのでしょうか？

```
実行結果
# python step1_ng.py
Traceback (most recent call last):
  File "step1_ng.py", line 5, in <module>
    user = client['User_Customer'].getObject()
  File "/usr/lib/python2.6/site-packages/SoftLayer/API.py", line 320, in call_handler
    return self(name, *args, **kwargs)
  File "/usr/lib/python2.6/site-packages/SoftLayer/API.py", line 288, in call
    return self.client.call(self.name, name, *args, **kwargs)
  File "/usr/lib/python2.6/site-packages/SoftLayer/API.py", line 187, in call
    return self.transport(request)
  File "/usr/lib/python2.6/site-packages/SoftLayer/transports.py", line 149, in __call__
    raise _ex(ex.faultCode, ex.faultString)
SoftLayer.exceptions.SoftLayerAPIError: SoftLayerAPIError(SoftLayer_Exception): Object does not exist to execute method on. (SoftLayer_User_Customer::getObject)

```



# object IDの指定

もう一度getObject()をよく見てみましょう。
http://sldn.softlayer.com/reference/services/SoftLayer_User_Customer/getObject
![required_headers.jpg](https://qiita-image-store.s3.amazonaws.com/0/62127/9fc49307-fc1c-7f5e-66a5-a62ad17abac3.jpeg)

よくよく見てみると、Required Headers（必須のヘッダー）として2つ記載があります。ここで、**authenticate**は認証が正しく済まされていることを指しています。よって、このRequired Headersに**authenticate**しか記載がないのであれば、特に考慮は不要です。問題は**SoftLayer_User_CustomerInitParameters**の所です。これは、このmethodを実施する際に、**SoftLayer_User_Customer ~~InitParameters~~**データ型オブジェクトのIDが必要だということを指しています。

よくよく考えてみると、getObject()というmethod名から判断すると、単数のオブジェクト（１つのユーザー）が返されるように思います。普通は、「"このユーザー"のユーザー情報を知りたい」のように、何かしらの**特定付ける条件**が必要なのは当然な気がしますね。

というので、まとめましょう。

* **「ルール6：methodのRequired Headersに、authenticate以外にSoftLayer_XXXXXXXInitParametersというパラメーターが必須の場合がある。この場合、このmethodを実行する際には、SoftLayer_XXXXXXXというデータ型オブジェクトのローカルプロパティであるid（object ID）が必要になる。」**

```py:step1_ok.py
import SoftLayer
import pprint
pp = pprint.PrettyPrinter(indent=4)
client = SoftLayer.create_client_from_env()
user = client['User_Customer'].getObject(id=183372)
pp.pprint(user)
```

# どうやってobject IDを取得すればよいのか？
そのid=183372って、そもそもどうやって調べるのよ？っていう疑問は当然です。
'SoftLayer_User_Customer'データ型オブジェクトを返してくれるようなmethodで、なおかつそのmethodのRequired Headersがauthenticateだけであれば、引数無しで実行できるのですが、、、、そもそもそんな都合が良いServiceとmethodを見つけるのは慣れが必要です。とはいっても、それが見つけられないと何も始まらないのですが。。。

１つの手がかかりは、該当するデータ型オブジェクトのrelational propertyを眺めてみることです。例えば、今回の'SoftLayer_User_Customer'は、そのrelational propertyとしてAccountが存在することが分かります。そこで、SoftLayer_User_CustomerとAccountは密接な関係があるのだろうと**想像を働かせ**、AccountにてSoftLayer_User_Customerデータ型オブジェクトを返してくれるようなmethod（ただし、Required Headersがauthenticateに限るもの。取得例１）やrelatoinal property（取得例２）がないかを探してみるのです。ユーザーはアカウントに紐づいていることを鑑みると、この両者に関連性があることは不思議ではありません。このように、relational propertyを見て関連するオブジェクトを辿れないかを検討してみるのは１つのコツと言えるでしょう。

SoftLayer_User_Customerのobject ID取得例1

```py:getuserid1.py
import SoftLayer
import pprint
pp = pprint.PrettyPrinter(indent=4)
client = SoftLayer.create_client_from_env()
users = client['Account'].getUsers(mask='id, username')
pp.pprint(users)
```

SoftLayer_User_Customerのobject ID取得例2

```py:getuserid2.py
import SoftLayer
import pprint
pp = pprint.PrettyPrinter(indent=4)
client = SoftLayer.create_client_from_env()
users = client['Account'].getObject(mask='id, users[id, username]')
pp.pprint(users)
```


今回はここまで！