megutech

自身の備忘録として主にWEBサーバー周りの技術について投稿しています。

Ruby on RailsでInstagram Graph APIを使いたい

Ruby on Rails上でInstagram Graph APIを使う情報が少なかったので、はまりポイントも併せて備忘録を残していく。

環境

Service Version
Ruby 3.2.2
Ruby on Rails 7.0.4
devise 4.9.2
omniauth-oatuh2 1.3.1
omniauth-rails_csrf_protection 0.1.2
omniauth-facebook 9.0.0
koala 3.4.0

構築

下準備

まずはどんな環境でも必須となる、下記準備を行ってください。

  1. Instagramでビジネスアカウントを作成する
  2. Facebookでアカウントを作成する
  3. Facebookページを作成する
  4. FacebookページとInstagramのビジネスアカウントを連携させる

実装

やることは以下です。

  1. omniauth-facebookでAccessToken取得
  2. 取得したAccessTokenからFacebookページ用のAccessToken取得
  3. Facebookページ用のAccessTokenを使ってInstagram Business Account IDを取得

事前準備

まずはMeta Developerでアプリを作成し、アプリIDとapp secretを取得してください。
そしてFacebookログイン/Instagram Graph API設定を行ってください。

config

まずはomniauthの設定。

一応v16を使おうと思ったのでclient_optionsを指定していますが、ここは不要だと思います。
scopeに関してもとりあえず詰め込んでいますが、ご自身で精査してください。私も後で精査予定。

config/initializes/devise.rb

  config.omniauth :facebook,
    Rails.application.credentials.dig(:facebool, :app_id),
    Rails.application.credentials.dig(:facebool, :app_secret),
    {
      client_options: {
        site: 'https://graph.facebook.com/v16.0',
        authorize_url: "https://www.facebook.com/v16.0/dialog/oauth"
      },
      scope: 'instagram_basic,instagram_content_publish,instagram_manage_comments,instagram_manage_insights,instagram_shopping_tag_products,pages_show_list,pages_read_engagement,instagram_manage_messages'
    }

callback

ここまでは普通のomniauthなので難しくはないと思うので、viewだとかは省略。

ここからは取得したTokenを使ってInstagram Graph APIを使用できるTokenを取得します。

omniauth_callbacks_controller.rb

  def facebook
    token = request.env['omniauth.auth']['credentials']['token']

    # 実際はページングとかもありますが、この解説では無視します。
    accounts = Koala::Facebook::API.new(token).get_connections(:me, :accounts)
    accounts.each do |account|
      graph = Koala::Facebook::API.new(account["access_token"])
      me = graph.get_object(:me, { fields: :instagram_business_account })

      ib_id = me["instagram_business_account"]["id"]
      access_token = account["access_token"]

      # something process
    end

    # something process
  end

fetch media

上記で取得したib_idaccess_tokenを使うことで、Instagram Graph APIを利用できます。

media_field = [:id, :media_url, :caption, :media_type, :thumbnail_url ]
graph = Koala::Facebook::API.new(access_token)
live_media = graph.get_connections(ib_id, "live_media", { fields: media_field })

やったぜ!!

はまりポイント

その1

Q: Facebook/Instagramって別物なの?

ドキュメントを読むと同じエンドポイントっぽいけど、omniauth-instagram-graphinstagram_graph_apiのようなInstagram特化gemがあるよ?

A: 同じです。

それらのGemは使う必要はないです。

omniauth-instagram-graphは名前にgraphって入ってるのに、発行されるtokenはInstagram Basic Display APIようのものでした。
それっぽい名前使うんじゃねぇ!と言いたいところ。
何か意図があるのかしら。。。

instagram_graph_apiは使ってもよいかも。
omniauthで取得したAccessTokenを食わせれば、callbackの部分に書いた内容を丸っと肩代わりしてくれるかもしれない。
ただ更新が3年前で止まっているので今回は見送りました。
koalaで普通にいけるしね。

その2

Q: Tried accessing nonexisting field (media) on node type (User)

下準備はしっかり行ったのに、エラーが出るよ?

A: Access Tokenは3種類ある!

最初はomniauthで取得できるAccessTokenを使用し、かつ{ig-user-id}部分をmeで対応していた。
しかしこれは両方ともダメ。

まずAccessTokenは以下の三種類存在するが、最後のページのTokenを利用する必要がある。

  1. OAuthで取得できるToken
  2. 長期化したToken
  3. 各ページごとのToken

omniauth-facebookは第2トークンまでは勝手に取ってくれる。
第3トークンは実装編に書いている通り。

第2トークンを使っていると、Tried accessing nonexisting field (media) on node type (User)というエラーが出る。
これに長らくはまってしまった。

そしてこれまたはまりポイントが、{id-user-id}はちゃんと指定しなければならない。
この取得方法が最初は分からず、ここも詰まってしまった。 そんな中に見つけた下記サイトにヒントを得て、実践編の形に落ち着いた。
https://tsushiru.com/sns/instagram-graph-api-get-access-token-and-business-account-15-0-2.html

所感

APIFacebook Graph APi/Instagram Graph API/Instagram Basic Display APIと三種類もあるし、
AccessTokenもInstagram Basic Display API用やら短期/長期/ページ用等複数あるし、
app id/app secretもFacebookのものとInstagram Basic Display API用のがあるし、
まずそもそもInstagram Graph APIを使うにはビジネスアカウントにしたりFacebook Pageと連携が必要だったり、
むっずかしいな!!