58
47

【図解】個人サービスを例に、Web APIの概要とRailsでの使い方を一番分かりやすく説明する

Last updated at Posted at 2021-10-10

※記事に登場する個人サービスは終了済です。

記事の目的

  • 「そもそもWebAPIとは?」って人がWebAPIの概要を理解できる
  • Rails初学者がWebAPIの使い方を理解できる

この記事を理解できる人

  • Webにおけるリクエストレスポンスのイメージを、なんとなくでいいので理解している人
  • ProgateのRubyRailsを完走できるレベルの人(WebAPIの概要だけ見るなら不問)

目次

例に出すサービスの内容
APIとは
APIが分かりにくい2つの理由
Railsでの一番簡単な使い方 リクエスト編
Railsでの一番簡単な使い方 レスポンス編
まとめ
補足(JSONとは?)
開発環境

例に出すサービスの内容

サービス概要

いらないもの診断というお片付けアプリです。

アップロードされた写真から「いらないもの」を発見します。

使用しているWebAPI

「いらないもの診断」では、写ったモノを検出できる「Cloud Vision」という
Google製のWebAPIを使っています。

APIとは

APIとは「Application Programming Interface」の頭文字です。
Interface(インターフェース)とは直訳で「接点」であり、コンピュータ用語では
「何かと何かをつなぐもの」です。

ソフトウェアだとイメージが湧かないかもしれませんが、
ハードウェアだと例えばケーブル類は「何かと何かをつなぐ」のでインターフェースの一種です。

では、「何のための、何と何をつなぐ接点」なのか?

一言でいうと、APIは「アプリがアプリを使うための、アプリとアプリをつなぐ接点」です。
そして、中でもWeb上のリクエスト/レスポンスを利用する「接点」を「WebAPI」といいます。
(APIは総称であり、その中にWebAPIがあるというイメージを持てればOKです。
WebAPI以外のAPIもありますが、本題から逸れるのでここでは説明しません。)

※ここからは、便宜上WebAPIを「API」と呼んで説明します

図解するとこんな感じです。
Image from Gyazo
「いらないもの診断」を使っているとき、
一見すると人間がブラウザを操作して「いらないもの診断」を使っているだけのように見えますが、
実はその裏で「いらないもの診断」が「Cloud Vision」を使っています。

そして「API」とは、”使われる側”のアプリに設置する「ドア」のようなものだと考えれば分かりやすいでしょう。
このドアのおかげで「いらないもの診断」は「Cloud Vision」にアクセスし利用することができるのです。
※以下、”使う側”のアプリを「APIユーザー」、”使われる側”のアプリを「APIプロバイダ」と呼びます。
Image from Gyazo

APIが分かりにくい2つの理由

①実体がない

先ほどは分かりやすく説明するためにAPIを「ドア」に例えましたが、厳密にいうとAPIは
アプリがアプリを使うために必要な「仕組み」であり、実体のない抽象概念なのです。
(だから、「ドア」そのものに該当するコードを探しても見つかりません。)

初学者にしてみたら、APIという用語を理解するだけでも一苦労なのに、
その実体はなく、肝心の仕組みもAPIプロバイダの中にあるんだから、分かりにくくて当然です。

なので最初のうちは、上の図解でイメージを掴むだけでOKです。

②主語がない

調べていくうちに「APIを叩く」とか「APIを公開する」というようなワードを目にすると思いますが、
前者はAPIユーザー(今回でいう「いらないもの診断」)が主語で、
後者はAPIプロバイダ(今回でいう「Cloud Vision」)が主語です。

日常会話でも主語がなくて分かりにくいことはありますが、APIはその典型といえるでしょう。
ましてや、これからAPIを理解する人にとっては尚更です。

「API」という言葉に触れるときは、主語が「ユーザー」なのか「プロバイダ」なのか、最初に考えてみると良いでしょう。

Railsでの一番簡単な使い方 リクエスト編

自分のアプリでAPIを利用するとき、通常のアクションとの一番の違いは「アプリがアプリにリクエストを送る」という点です。
Image from Gyazo

ブラウザはURLの送信やリンクのクリックによってリクエストを送信しますが、
Railsアプリでリクエストを送る場合はこうです。

xxxx_controller.rb
require 'net/http'

def xxx
  # ②APIキーを定義
  api_key = "xxxxxxxxxxxxx"
  # ③リクエストURLを定義
  api_url = URI("https://vision.googleapis.com/v1/images:annotate?key=#{vision_api_key}")
  # ④リクエストボディを定義
  body = {
      requests: [
        {
          features: [
            {
              maxResults: 10,
              type: "OBJECT_LOCALIZATION"
            }
          ],
          image: {
            content: "画像URLを記載"
          }
        }
      ]
    }.to_json
  # ⑤リクエストヘッダーを定義
  headers = { "Content-Type" => "application/json" }
  # ①リクエストを送信し、返ってきたレスポンスを変数responseに格納
  response = Net::HTTP.post(api_url, body, headers)
end

以下ひとつずつ解説していきます。

response = Net::HTTP.post(api_url, body, headers)

Net::HTTP.postメソッドによってAPIプロバイダにリクエストが送信され、そのレスポンスが変数responseに格納されています。

ちなみに今回はPOSTリクエストを送りたかったのでNet::HTTP.postというメソッドですが、GETリクエストを送りたい場合は
Net::HTTP.getというメソッドになります。
(GET/POSTなどのいわゆる「HTTP動詞」はAPIプロバイダが指定するものなので、
自分が使いたいAPIプロバイダの公式リファレンスを見てください)

引数であるapi_url, body, headersについては以下で解説します。

api_key = "xxxxxxxxxxxxx"

APIキーとは、文字通りAPIを使うために必要な認証キーです。

人間がアプリを使うときは、メールアドレスパスワードを認証キーとしてログインする場面がよくあると思いますが、
アプリがアプリを使うときはこのAPIキーが認証キーとなります。

さっきの図でいうと、「ドア」であるAPIを開けるための「鍵」です。
Image from Gyazo
このAPIキーはパスワードと同じで他人には絶対知られてはいけないのですが、
コントローラはGitHubなどから見れてしまうので、実は上の書き方は推奨されません。

Rails5.2以上ならconfig/credentials.yml.encを使うのがおすすめです。
credentials.yml.encはざっくりいうと「秘匿性のある情報を安全に保管できるファイル」です。(詳しくはRailsガイド参照)

ここに

credentials.yml.enc
api_key: xxxxxxxxxxxxxxxxxxx

と書けば、以下のより安全なコードに書き換えることができます。

xxxx_controller.rb
api_key = Rails.application.credentials.api_key

基本的にAPIキーはAPIプロバイダに発行してもらうものなので、
使いたいAPIプロバイダの公式リファレンスで発行してもらうようにしてください。
(中にはAPIキーなしで使えるものもあるようです。)

api_url = URI("https://vision.googleapis.com/v1/images:annotate?key=#{api_key}")

ここはAPIプロバイダであるCloud Visionの公式リファレンスに従っているだけなので、
他のAPIプロバイダを使いたいときはその公式リファレンスに従ってください。

URLの文字列そのままではNet::HTTP.postメソッドの引数として適切な記法ではないためURIメソッドを使っていますが、
本題ではないので割愛します。

また認証をパスするため、?key=#{api_key}の部分でパラメータにAPIキーを渡しています。

body = { ... }.to_json 

{ }の中はurl同様、APIプロバイダの公式リファレンスに従ったまでです。
同じく公式リファレンスで「JSON形式にしろ」と言われているので、to_jsonメソッドでJSON形式に変換しています。

headers = { "Content-Type" => "application/json" }

リクエストヘッダーを決めるための記述です。
今回はJSON形式でリクエストを送信したいので"Content-Type" => "application/json"を指定しました。
(昨今のAPIのやりとりのほとんどがJSON形式なので、基本的に必要になる記述だと思います)

他に指定したい項目がある場合は
{ "Content-Type" => "application/json", "xxx" => "xxx", "xxx" => "xxx", ... }
みたいに複数指定することもできます。

Railsでの一番簡単な使い方 レスポンス編

response = Net::HTTP.post(api_url, body, headers)

この一文によって、APIプロバイダが返してくれたレスポンスは既に変数responseに格納されています。

「Cloud Vision」の場合、例えばこの写真をリクエストとして送信すると、
Image from Gyazo
以下のようなJSON形式でレスポンスを返してくれます。

   {
  "responses": [
    {
      "localizedObjectAnnotations": [
        {
          "mid": "/m/01bqk0",
          "name": "Bicycle wheel",
          "score": 0.89648587,
          "boundingPoly": {
            "normalizedVertices": [
              (中略)
            ]
          }
        },
        {
          "mid": "/m/0199g",
          "name": "Bicycle",
          "score": 0.886761,
          "boundingPoly": {
            "normalizedVertices": [
              (中略)
            ]
          }
        },
        (中略)
      ]
    }
  ]
}

長いので一部割愛しましたが、写真に映ったモノの名前を返してくれていることが分かるでしょう。

あとはこの中の使いたい部分を取り出すことができれば、無事「APIを使えた」ことになります。
では解説していきます。

上述のレスポンスの内容はresponse.bodyで呼び出すことができますが、
映ったモノの名前など、さらに奥にあるデータを取り出すには
JSON.perseメソッドでRubyオブジェクトに変換することをおすすめします。

JSON.parse(response.body)

これにより、まるでハッシュや配列から値を取り出すように、欲しいデータを取り出すことができます。

例えば、最初に検出したモノの名前を取り出したければこうです。

JSON.parse(response.body)['responses'][0]["localizedObjectAnnotations"][0]['name']
# => "Bicycle wheel"

言葉にすると、
「responses配列の一番最初の要素の、localizedObjectAnnotations配列の一番最初の要素の、nameキーに対応する値」
ということになります。

筆者の場合は映ったモノの名前を全て取り出し、それを配列にしたかったのでこうです。

JSON.parse(response.body)['responses'][0]["localizedObjectAnnotations"]&.map {|i| i['name']}
# => ["Bicycle wheel", "Bicycle wheel", "Bicycle", "Picture frame"]

今回は構造が複雑なので難しく感じますが、ハッシュや配列から要素を取り出す方法はProgate(ruby)でも学習したと思います。
必要に応じて復習しながら、あなたの用途に合わせて記述を変えてみるといいでしょう。

まとめ

  • APIとは?
    • アプリがアプリを使うために必要な「仕組み」
    • あくまで「仕組み」(抽象概念)であり、実体はない
    • APIにはユーザーとプロバイダが存在する
  • RailsにおけるAPIの使い方
    • リクエスト編
      • APIプロバイダの公式リファレンスを参考に、リクエストに必要なURL、APIキー、ボディ、ヘッダーを定義する。
      • 定義した変数を引数に入れ、Net::HTTPメソッドでリクエストを送信する。
    • レスポンス編
      • 返ってきたレスポンスをJSON.perseメソッドでRubyオブジェクトに変換する。
      • ハッシュや配列から要素を取り出すのと同じ要領で、自分の欲しいデータを取り出す。

補足 JSONとは

Railsの学習初期ではあまりJSON形式は出てこないのでハードルが高いと感じるかもしれませんが、あくまで書き方のひとつです。

人間やブラウザがアプリを使うときは、人間にとって読みやすいHTML形式でレスポンスが返ってきますが、
アプリがアプリを使うときは、機械にとって読みやすいJSON形式でレスポンスが返されているというだけのことです。
Image from Gyazo
なので、はじめは「そういう書き方があるんだ」という認識でもいいと思います。

開発環境

Ruby 3.0.0
Rails 6.1.4.1

その他

  • 記事の分かりにくい箇所や過不足、誤りなどあればコメントいただけると幸いです。
  • 本サービスのコード詳しく知りたい場合はGitHubをご覧ください。
    • (記事のコードは分かりやすさ重視のため、GitHubと若干コードが異なる部分もあります)
58
47
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
58
47