ShinobiLayer: SoftLayer API 次の一歩: データ型オブジェクト(1)

#はじめに
昨年一年の間、SoftLayerでの研修などで講義をしていて、APIとVyatta Gateway Applianceについては説明不足（オリジナルの講義資料に元々記載がなかった）を感じていていました。
slコマンドも随時拡張されてはいますし、ちょっとした利用には重宝するのですが、やはり自分がやりたい事をピンポイントで実装しようとなると、直接API Referenceを参照しながら実装が必要になります。
SoftLayerのAPIは非常に強力なツールなのですが、API Referenceは一見（？）癖があり、どうやって呼び出せば良いかが分からない方もいらっしゃるのではないかと思います。
というので、今後数回に分けて、API Referenceの読み方とコードの書き方を紹介したいと思います(Vyatta Gateway Applianceについてはまた別の機会に）。

*なお、この記事で書いているルールは100%どこかに書いている内容ではなく、私の経験から作られたものなので、正式な表現ではないかもしれないことを、予めお詫びしておきます。*

#前提

* 使用言語: Python（SoftLayerでのスタンダード。slコマンドもPythonを使って実装されています）
* slコマンドのsetupが既に完了していること。以下の記事などによくまとめられています。
 - http://niccloud.niandc.ne.jp/?p=892
 - http://www.creationline.com/lab/3893


#今回の目標
今回は、

* ServiceオブジェクトとData Type（データ型）オブジェクトの違いを理解する。
* maskの記述方法を習得し、local property、relational property、count propertyへのアクセス方法を理解する。

のが目標です。たかが「プロパティでしょ？」と思うなかれ。このプロパティへの柔軟なアクセス方法（特にRelational Property）がSoftLayer APIを理解する上で大きなポイントになります。methodではなく、データ型オブジェクトを最初に説明しているのはこのためです。

#APIをまずは眺めてみる

SoftLayerのAPI Referenceを見てみましょう。例えば、AccountというServiceとData Typeを眺めてみてもらえば気が付くことが、幾つかあると思います。
http://sldn.softlayer.com/reference/services/SoftLayer_Account
http://sldn.softlayer.com/reference/datatypes/SoftLayer_Account

* Serviceにしか存在しないオブジェクト（例：Account_Historical_Report）や、Data Typeにしか存在しないオブジェクト（例：Account_Contact_Type）があります。

* Serviceにはmethod一覧が載っています。Serviceオブジェクトに存在するmethodが返すのは、
    * 「リテラル（数字、文字列、論理値など）」
    * 「データ型オブジェクト」
    * 「データ型オブジェクトの配列」
    
    などであり、methodがServiceオブジェクトを返すことはないようです。methodの呼び出し方法の詳細については別途説明の機会を設けたいと思います。

* Data Type（データ型）オブジェクトの構成として、local property, relational property, count propertyの3種類が存在します。例えば、Accountデータ型オブジェクト自身は、Account情報（アカウント名や住所情報など。local propertyに相当）しか持たないかもしれません。しかし、そもそも皆様が利用している仮想サーバーは皆様のAccountに紐づいている筈です。つまり、Accountデータ型オブジェクトは仮想サーバーのデータ型オブジェクトや物理サーバーのデータ型オブジェクトと何らかの**関係性**が存在するハズです。そうした**関連**をrelational propertyやcount propertyという形で表現しています。

    * local property: idなど。データ型オブジェクト自身の属性値
    * relational property: 自身と紐付けられた別の属性値。
    * count property: relational propertyの数。（あまり使う機会はない気がする）

* 具体的にAPIを見てみましょう。
http://sldn.softlayer.com/reference/datatypes/SoftLayer_Account のrelational propertyを見ると、以下のようになっているので、１つのSoftLayer_Accountデータ型オブジェクトには複数の"SoftLayer_Virtual_Guest"オブジェクトが紐づいていることが分かります。
![Account_to_virtual.jpg](https://qiita-image-store.s3.amazonaws.com/0/62127/7744a048-fd27-47c1-1029-e358b53e285d.jpeg)
一方で、http://sldn.softlayer.com/reference/datatypes/SoftLayer_Virtual_Guest のrelational propertyを見ると、1つのSoftLayer_Virtual_Guestデータ型オブジェクトには1つのSoftLayer_Accountが紐づいていることが分かります。
![virtual_to_account.jpg](https://qiita-image-store.s3.amazonaws.com/0/62127/75c97c0b-3619-0a6f-bfab-48f7ea34d044.jpeg)
つまり、（当然予想されたことですが）SoftLayer_AccountとSoftLayer_Virtual_Guestというデータ型の間には1:Nの関係性が存在します。


# Step1 - local propertyを全部取得する

```py:step1.py
import SoftLayer
import pprint
pp = pprint.PrettyPrinter(indent=4)
client = SoftLayer.create_client_from_env()
acct = client['Account'].getObject()
pp.pprint(acct)
```
まずは、この基本形を理解しましょう。json形式をそのまま出力すると可読性が低いので、pprintを使って整形しています。重要なポイントは、

* **「ルール1：`client['Service名']`で、Serviceオブジェクトを呼び出す。ただし、`client['SoftLayer_Account']`と書いても良いし、`client['Account']`のように"SoftLayer_"の部分を省略しても良い。」**。今回は、`client[Account]`でAccount Serviceを呼び出しています。これにより、AccountというServiceオブジェクトに属するmethodを呼び出すことが可能になります。

*  **「ルール2: `client['Service名'].method`は、Serviceオブジェクトを返さない。返すのはリテラル(stringやbooleanなど）、データ型オブジェクト、データ型オブジェクトの配列である。」**
つまり、`acct = client['Account'].getObject()`のところを、`acct = client['Account'].getObject().getObject()`のように書くとエラーになります。`client['Account'].getObject()`が返すのは、Accountというデータ型オブジェクトであり、AccountというServiceオブジェクトではありません。データ型オブジェクトに対してmethodは持っていませんのでエラーになります。
methodの返り値はServiceオブジェクトにならない（methodを含むオブジェクトにはならない）ということは、`client['Account'].getXXX().getYYY()`みたいな記述（ここでは、getXXX()やgetYYY()はAccount Serviceオブジェクトで定義されたmethod）はできないことを意味します。**ServiceオブジェクトとData Type（データ型）オブジェクトで同じ名称のものがありますが、名称が同じだけでその実は全く別物**だと考えておいた方がよいでしょう。

* **「ルール3：local propertyに対するmask指定がない限り、そのオブジェクトの"localプロパティ全て"が取得される」**というのが仕様のようです。この仕様もどこにも明確に書かれていませんが、経験上そういう動きをしていると思われます。今回は、`client['Account'].getObject()`が返すAccountデータ型オブジェクトのlocal property全てが表示されます。maskの詳細ついては次節以降で紹介します。ここでは、maskというキーワードが書かれていないことに納得しておいていただければ問題ありません。

```
実行結果
# python step1.py
{   'accountManagedResourcesFlag': False,
    'accountStatusId': 1001,
    'address1': 'xx-xx, xxxxxx-xxxxxxx',
    'allowedPptpVpnQuantity': 2,
    'brandId': xxxxx,
    'city': 'Tokyo',
    'claimedTaxExemptTxFlag': False,
    'companyName': 'xxxxx',
    'country': 'JP',
    'createDate': '2014-03-20T09:47:39-07:00',
    'email': 'xxx@xxxxxxxxx',
    'firstName': 'xxx',
    'id': xxxxxx,
    'isReseller': 0,
    'lastName': 'xxxxxx',
    'lateFeeProtectionFlag': True,
    'modifyDate': '2014-03-20T09:48:11-07:00',
    'officePhone': 'xxx-xxxx-xxxx',
    'postalCode': 'xxx-xxxx',
    'state': 'OT',
    'statusDate': ''}
```

続きはこちら！
http://qiita.com/testnin2/items/6be9b87571a99e01002a