【iOS】Google People APIでユーザーの情報を取得する

# はじめに
前の記事（[【iOS】Gmail APIを使って、ユーザーの複数のGmailアカウントからメールを取得する。](http://qiita.com/ryokkkke/items/dd04bea2b579c16a9b19)）の半分続きで、iOSアプリからGoogle のPeople APIを使ってみようと思います。

これもまた謎に迷うトラップがいくつかあるので...

今回はユーザーの名前と、メアドを取得したいと思います。

# Google People API
リファレンスはこちら：[Introduction  |  People API  |  Google Developers](https://developers.google.com/people/)

2016年の2月に発表されているのでわりかし最近、って書こうとしたけど2016年2月はもはや最近ではなかった😇

[Google Developers Japan: People API を公開しました](https://developers-jp.googleblog.com/2016/02/people-api.html)

## Plus APIは？
同じようなこと（ユーザーの情報を取得する）をするAPIに、[Google Plus API](https://developers.google.com/+/)が存在します。
このPlus APIなんですが、[iOSのGoogle+ Sign-In](https://developers.google.com/+/mobile/ios/)は2017年6月現在Deprecatedになっています。

ただ、RESTのPlus API（[Plus API for web](https://developers.google.com/+/web/)）は特にそういうことはありません。

ちょっとこの辺の関係性がよく分かりませんが...People APIを新しく開発してるということはPlusの方じゃなくてPeople使ってよということなのかな。

## People APIの仕様変更

最近(2017年6月)People APIに突然の仕様変更があったらしく、使っていた人たちに少し影響があったようです。
[Google People API “Request mask cannot be empty” - Stack Ovewflow](https://stackoverflow.com/questions/43901706/google-people-api-request-mask-cannot-be-empty)

ようですっていうか僕もそれで戸惑ったうちの一人なのだけども...後述します。

ここでは「People API使えなくなったけど、Plus APIで同じことができるからPlusに変えたよ」というような話が上がってますが...それで大丈夫なのかな


## ライブラリ
最初勝手にライブラリないだろと思って、PlusのAPIを`URLSession`を使って直にリクエスト送ってたんですが、よく探したら**PlusもPeopleもライブラリがありました。**

せっかくなので実装では`URLSession`を使ったやり方も載せておきます。


# 共通の準備

※細かいAPI使用前の準備（Google DevelopersでのApp作成、認証情報作成など）は前の記事（[【iOS】Gmail APIを使って、ユーザーの複数のGmailアカウントからメールを取得する。](http://qiita.com/ryokkkke/items/dd04bea2b579c16a9b19)）に書いているので割愛します。

## APIの有効化
まず、[Google APIsの方で、People APIを有効化します](https://console.developers.google.com/apis/api/people.googleapis.com/overview)。

## スコープ
それから、スコープを付け足します。

```swift
private let scopes = [
    "https://www.googleapis.com/auth/userinfo.profile", 
    "https://www.googleapis.com/auth/userinfo.email"
]
```

でこのscopeの文字列も、どれが正しいのか微妙に不明なのですが...
People APIの[Authorize Requests  |  People API  |  Google Developers](https://developers.google.com/people/v1/how-tos/authorizing#profile-scopes)では、`profile`と`email`があります。なんでこれだけURLじゃないんだろう。

[OAuth 2.0 Scopes for Google APIs  |  Google Identity Platform  |  Google Developers](https://developers.google.com/identity/protocols/googlescopes#peoplev1)では、People APIのprofileとemailのスコープはそれぞれ

```
email   : "https://www.googleapis.com/auth/userinfo.email"
profile : "https://www.googleapis.com/auth/userinfo.profile"
```
になっています。
後述するライブラリのスコープの定数はこのページの値（URLになっている方）と同じでした。
なので、URLになっている方にするべき...というかライブラリの定数を使いましょう（）

ちなみにURLでない"profile"と"email"だけでもPlus APIは実行できました。

# 実装

## URLSession
URLSessionを直に使ってAPIを叩く場合は以下の感じになります。

```swift
let session = URLSession(configuration: URLSessionConfiguration.default)
var request = URLRequest(url: URL(string: "https://www.googleapis.com/plus/v1/people/me")!)
// Authorizationヘッダにて認証情報を指定
request.addValue("Bearer \(accessToken)", forHTTPHeaderField: "Authorization")
let task = session.dataTask(with: request) { (data, response, error) in
    if ((error) == nil) {
        print(NSString(data: data!, encoding: String.Encoding.utf8.rawValue)!)
        do{
            // レスポンスをJSONパース
            let responseJson = ( try JSONSerialization.jsonObject(with: data!, options: JSONSerialization.ReadingOptions.allowFragments) as! NSDictionary)
            let email = ((responseJson["emails"] as! NSArray)[0] as! NSDictionary)["value"] as! String
            let displayName = responseJson["displayName"] as! String
            print(email)
            print(displayName)
        }catch{
            print("JSONパースに失敗しました。")
        }
    } else {
        print("Google People APIへのリクエストに失敗しました。")
    }
};
task.resume()

```

気をつけるところと言えばアクセストークンをヘッダに付与する部分でしょうか↓

```swift
// Authorizationヘッダにて認証情報を指定
request.addValue("Bearer \(accessToken)", forHTTPHeaderField: "Authorization")
```

参考：[トークンを利用した認証・認可 API を実装するとき Authorization: Bearer ヘッダを使っていいのか調べた](http://qiita.com/uasi/items/cfb60588daa18c2ec6f5)

アクセストークンは、

```swift
// authorization: GTMAppAuthFetcherAuthorization
authorization.authState.lastTokenResponse?.accessToken
```

とかで取得できます。
`GTMAppAuthFetcherAuthorization`に関しては前の記事を参照ください。


この方法ならPeople APIに限らずどれでも実行できますが、まあライブラリ使いましょう...

## ライブラリ

Podfileを以下のようにして、`pod install`します。

```:Podfile
platform :ios, '8.0'
use_frameworks!
target 'TestApp' do
    pod 'GoogleAPIClientForREST/PeopleService', '~> 1.3.0'
    pod 'GTMAppAuth'
end
```

`GoogleAPIClientForREST/People`ではなく`GoogleAPIClientForREST/PeopleService`であるところに気をつけてください。
[google-api-objectivec-client-for-rest/GoogleAPIClientForREST.podspec](https://github.com/google/google-api-objectivec-client-for-rest/blob/master/GoogleAPIClientForREST.podspec#L325-L327)を見ると分かりやすいです。

なんでPeopleだけは"Service"ってついてるんだろう。

以下コードです。

```swift
let query = GTLRPeopleServiceQuery_PeopleGet.query(withResourceName: "people/me")
let service = GTLRPeopleServiceService()
service.authorizer = self.authorization
query.requestMaskIncludeField = "person.names,person.email_addresses"
service.executeQuery( query,
                      delegate: self,
                      didFinish: #selector(callback) )

```

他はmeだけがパラメータなのに、PeopleAPIのgetってなんで`people/`までパラメータになってるんですかね...
meだけだとだめなので、気をつけてください。

### requestMaskIncludeField
で、先ほど上で書いた仕様変更というのはこの`requestMaskIncludeField`というパラメータについての話です。

このパラメータ、ちょっと前までは任意だったのですが、**現在は必須項目になっています。**
これが、リファレンスも一部しか更新されておらず、中身の仕様だけ変わるという鬼の所業...
もちろんライブラリもまだ更新されていません。

[RequestMask  |  People API  |  Google Developers](https://developers.google.com/people/api/rest/v1/RequestMask)を見ると確かにRequiredとなっているのですが、[Method: people.get  |  People API  |  Google Developers](https://developers.google.com/people/api/rest/v1/people/get)では必須ではないことになっています。

まあともかく、**2017年6月現在は`requestMaskIncludeField`パラメータは必須です。**

つけないと、`Request mask can not be empty.`というエラーが返ってくるので注意してください。

コードにおいては、クエリオブジェクトのイニシャライザで指定する方法がないので、

```swift
query.requestMaskIncludeField = "person.names,person.email_addresses"
```

このようにオブジェクト生成後にプロパティに代入します。

ちなみに使える値は2017年6月現在、

```
person.addresses
person.age_ranges
person.biographies
person.birthdays
person.bragging_rights
person.cover_photos
person.email_addresses
person.events
person.genders
person.im_clients
person.interests
person.locales
person.memberships
person.metadata
person.names
person.nicknames
person.occupations
person.organizations
person.phone_numbers
person.photos
person.relations
person.relationship_interests
person.relationship_statuses
person.residences
person.skills
person.taglines
person.urls
```

の27種類です。

その他は他のAPIと特に変わったところはないです！

### コールバック

```swift
func callback( ticket : GTLRServiceTicket,
                        finishedWithObject response : GTLRPeopleService_Person,
                        error : NSError? ){
        if let error = error {
            print("プロフィールの取得に失敗しました。")
            print(error)
            return
        }
        print("プロフィールの取得に成功しました。")
        print(response.names)
        print(response.emailAddresses)
        
    }
```

実行すると、ちゃんと取れてることがわかると思います！