InstagramAPIからInstagram Basic Display APIへの移行

#InstagramAPI廃止のお知らせ（~~2020/3/31まで~~ → ２０２０/６/２９まで）
https://www.instagram.com/developer/
こちらを読んでもらうとわかるのですが、~~InstagramAPIは2020/3/31にて廃止されます。~~

とありましたが、2020/6/29まで延期されました。
（3/31から90日間ほど延期）

そのため、InstagramAPIを使用しているものは新しいAPIに変更する必要があります。

#新しいAPIはFacebookから提供
Instagram自体はFacebookが提供しているサービスなので、Facebookが用意するAPIを使用することになりました。
新しいAPIについてはこちらにドキュメントが揃っています。
https://developers.facebook.com/docs/instagram

#Facebookから提供されているInstagramプラットフォーム
##種類と（ざっくり）概要

|種類|概要|
|:-----------------|:-----------------|
|Instagram Graph API|ビジネスアカウント向け|
|Instagram Basic Display API (日本語訳 Instragram基本表示API)|個人アカウント向け|
|フィードへのシェア||
|ストーリーズへのシェア||

Instagram基本表示APIしか試していないので、以下は基本表示APIのことしか書いていません
個人利用のAPI、2020年の1月あたりにリリースされましたね。
InstagramAPIのdevelopページは「なくなるよ」というメッセージがでてからしばらくはビジネスアカウント向けのものしかなかったので焦っていたところでした。

##Instagram基本表示APIについて
個人のInstagramアカウントの情報を取得
提供されるのは、基本データに対する読み取りアクセス権のみ
（メディアの公開やコメント管理などは不可）

##用途
- InstagramユーザーからInstagramユーザーアクセストークン及びアクセス許可を取得する
- Instagramユーザーのプロフィールを取得する
- Instagramユーザーの画像、動画、アルバムを取得する

##注意事項
Facebookへのログインを促すAPIではない。（Facebookのデータを取得することはできない）
ストーリーズ、コメント、インサイト、宣伝関連のことはサポートされていない

サイト内に自分のアカウントの写真を表示するという小さな用途なら
こちらのInstgram基本表示APIで事足りると思います。

##準備するもの
- アプリを作成できるFacebookアカウント（デベロッパー登録をしている個人アカウント）
- ログインできるInstagramアカウント（Instagramにログインして「承認」動作を行う箇所が2つほどある）
- 公開しているウェブサイト（サイトを公開していなくてもなんとかなります（私はlocalhostで行いました）。ただ、httpsサイトでないとバリデーションの段階でコケます）
- curlが実行できるツール（私は面倒なのでGoogle Chromeで使用できるARCというアプリを使用しました）

##補足
テストユーザーの画像取得という用途だけならアプリ申請の必要なし
（アクセストークンはアプリ申請しなくても取得できる）
長寿命のアクセストークンは60日有効なので、延命処置を検討する
（cronで一ヶ月毎に取得、アクセスされたときにトークンの寿命をみて再度トークンを取得など…）

##手順
（サマリーです）
1. Instagramフィード取得用のFacebookアプリを作成
2. 表示したいInstagramアカウントをテストユーザーとして招待
3. 2で招待したアカウントにて1で作成したアプリを承認
4. 2のアカウントに向けて認証ウィンドウを表示（ブラウザからアドレスを打つ）→
	Instagramにて承認する→認証用コードが発行される
5. 認証用コードを使用して、短命アクセストークンを取得
6. 長寿命のアクセストークンを取得
7. 6を使用して2のアカウントのInstagramフィードを取得
8. 7で取得したフィードを良い感じに加工してサイトに表示する
長寿命のアクセストークンは60日有効なので、延命処置を検討する
（cronで一ヶ月毎に取得とか）

##手順の説明
基本的に以下と書いてあることは同じです。この順番で行っています。

アクセストークンを取得
https://developers.facebook.com/docs/instagram-basic-display-api/getting-started
長寿命トークンの取得
https://developers.facebook.com/docs/instagram-basic-display-api/guides/long-lived-access-tokens
メディアの取得
https://developers.facebook.com/docs/instagram-basic-display-api/guides/getting-profiles-and-media

##実際に行ってみて気になったところ
以下はそれぞれの手順で個人的に躓いたところとか気になったところを書きます。
### 1. Instagramフィード取得用のFacebookアプリを作成
**アプリ名**
アプリ名に「`gram`」という単語は使用できません。
hogehogegramというようなInstagramをもじったような名前は使えないということなので気をつけましょう。

**ウェブサイト**
公開されているウェブサイトを指定する箇所ですが、公開していなくても指定できます。
ウェブの存在チェックは（おそらく）されていません。
ですが、頭が「https://」であることは必須のため、嘘でも良いのでhttps://を指定します。
（もちろんちゃんと申請して公開するFacebookアプリなら存在するURLを設定しましょう）

### 3.2で招待したアカウントにて1で作成したアプリを承認
テストユーザーとして招待したあとは、招待したユーザーアカウントでInstagramにログインします。

### 4.2のアカウントに向けて認証ウィンドウを表示（ブラウザからアドレスを打つ）→Instagramにて承認する→認証用コードが発行される

ドキュメントに太字でも書いてあるのですが、ここで指定するapp-idは「InstagramアプリID」です。FacebookアプリIDではなく、InstagramアプリIDです。
画面上部に常に表示されているアプリIDとは別物です。
プロダクト->Instagram->Basic Displayと遷移した後に下の方に表示される「InstagramアプリID」です。

このURLをブラウザのアドレスバーにはりつけて移動します。
移動後、Instagramの認証ウィンドウが表示されるので[許可]を押します。
[許可]を押した後は1で設定したウェブサイトにリダイレクトされます。
アドレスバーに認証コードが付加されたアドレスが表示されているので、コピーします。

存在しないURLを指定していた場合は「ページが表示されません」というようなエラーページに遷移します。
ただ、ここではページが表示されることよりもアドレスバーに表示されているトークンつきのアドレスのほうが重要なので、存在しないURLでも問題ありません。
この動作は「Instagramアカウント」に紐付いているので、Instagramアカウントにログインしてから行います。
ここで発行した認証用コードは「1時間のみ有効」であるので、素早く次の動作を行います。

### 5.認証用コードを使用して、短命アクセストークンを取得
先述の通り私はGoogleChromeのARCというアプリを使用しました。
POSTの際に「multipart/form-data」を選択して、bodyにそれぞれパラメータを付与してPOSTを投げました。

### 6.長寿命のアクセストークンを取得
ここからは以下の[Long-Lived Access Tokens]の内容になります。
https://developers.facebook.com/docs/instagram-basic-display-api/guides/long-lived-access-tokens
2020/3/11の時点では日本語訳は存在しないので、Google翻訳を片手に読みます。


翻訳内容をざっくりまとめると以下のようになります

- 短命トークンの有効期限は1時間
- 短命トークンは長寿命トークンと交換できる
- 長寿命トークンの有効期限は60日間
- ユーザーがアプリに「instagram_graph_user_profile」権限を与えている限り更新できる
- 期限切れトークンは更新できない
- 期限切れ短命トークンは長寿命トークンと交換できない
- アプリシークレットは漏らすな


#### 短命トークンを使用した長寿命トークンの取得
GET /access_token にリクエストをなげると長寿命トークンに交換される

```
curl -i -X GET "https://graph.instagram.com/access_token
  ?grant_type=ig_exchange_token
  &client_secret={instagram-app-secret}
  &access_token={short-lived-access-token}"
```
`{instagram-app-secret}`	instagramアプリシークレット
`{short-lived-access-token}`	短命トークン

返答例

```
{
  "access_token":"{long-lived-user-access-token}",
  "token_type": "bearer",
  "expires_in": 5183944  // Number of seconds until token expires
}
```
`expires_in`	期限切れまでの秒数

#### 長寿命トークンから新しい長寿命トークンの取得
GET /refresh_access_token にリクエストをなげると、長寿命トークンを新しく60日間有効な長寿命トークンに交換してくれる

```
curl -i -X GET "https://graph.instagram.com/refresh_access_token
  ?grant_type=ig_refresh_token
  &access_token={long-lived-access-token}"
```
`{long-lived-access-token}`	長寿命トークン

返答例

```
{
  "access_token":"{long-lived-user-access-token}",
  "token_type": "bearer",
  "expires_in": 5183944 // Number of seconds until token expires
}
```
`expires_in`	期限切れまでの秒数

期限がきれたトークンは使用できないので、期限が切れる前にトークンを新しくする必要がある。

以上です。
cronかなにかで定期実行させてトークンの延命処置をとるのが良いかと思っています。
cronが使えないならアクセスされた段階でトークンの寿命を見て新しく取得する…など…。

### 7.6を使用して2のアカウントのInstagramフィードを取得
ここからは[ユーザープロフィールとユーザーメディアの取得]の内容になる
写真だけなら[メディアデータを取得する]のところだけ実行する
https://developers.facebook.com/docs/instagram-basic-display-api/guides/getting-profiles-and-media

あとは良い感じに加工してサイトに写真を表示させて写真を自慢しましょう。

# 終わりに
他のAPIに関してはこれからじっくり見ていけたらと思います。

# 追記
2020/4/1 追記
Developerページを見ると、InstagramAPIの廃止日付が延期されていましたので、その旨を追記しました。