【Rails】外部APIを自社システムに連携するまでの流れを解説

## はじめに
どうもこんにちは、もきお([@mokio_50](https://twitter.com/mokio_50))です。
突然ですが上司から「このAPIうちのシステムで使えるよう実装しておいてもらえる？」と言われたら実装イメージは付きますでしょうか？

もちろんこんな雑なタスクの振り方はされないですが、当時の自分はさっぱりわけワカメ状態でした。なので今回はAPI連携には何が必要でどういうふうに実装したら良いのかを解説していきたいと思います。

あくまで実装の一例程度に見ていただけますと幸いです。

また実際に実装した一連の流れは以下の記事にまとめていますので合わせてご覧いただけますと幸いです。

https://qiita.com/mokio/items/6e65ff8572f303c18750

先日交流会でもLT登壇した際にこの話をしたので忙しければこちらでも！

https://docs.google.com/presentation/d/1ZqJGjvaKSLI-In6XAd_4fvknPLBzdOevkbR_XfJZFfU/edit#slide=id.g12adc8e8625_0_696

## 外部API連携とは？
実際の流れを解説する前にそもそもAPIってなんなの？外部API連携するとどういったことが起きるの？という方に向け、イメージとしてどんな感じなのかをお伝えできればなと思います。自分がイメージしているのがという話ですが。

APIは「Application Programming Interface」の略称で「アプリとプログラムを繋ぐもの」という意味ですよね。これを聞いて当時の自分は「繋ぐんだー。。でっ？」って感じでした笑
さっぱり意味わからん。

少しでもわかりやすくするために法人番号が取得できるAPIを例に考えてみましょう。

https://www.houjin-bangou.nta.go.jp/

こちらのサイトでは法人名や所在地などを入力し検索すると法人番号を調べることができます。
ブラウザ上で必要な情報を入力し検索(リクエスト)すると、法人番号というレスポンスを得ることができます。

これを自社アプリケーションなどで必要な情報をリクエストすると外部アプリケーションが欲しい情報をレスポンスしてくれる、その仲介をしてくれるのがAPIですかね。

外部アプリケーション(法人番号取得、YouTubeなど)を自社サービスに組み込むツールというか仕様書?みたいなものだと個人的には解釈しております。

画像だと以下がわかりやすかったです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1089852/8e639ef2-d72c-0e68-8eb6-bc7fdb161373.png)
引用元: [ビジネス＋IT](https://www.sbbit.jp/article/cont1/62752)


また情報を得るだけでなくAPI連携のメリットとして自社アプリケーションから外部アプリケーションのでの新規作成や更新を行うこともできたりします。

TwitterのAPIを使うといいねすることができたり、QiitaのAPIを使えば、Qiitaのブラウザ上でなくても記事の新規作成や更新をすることができます。

なので外部API連携するには必要な情報をリクエストし、どういったレスポンスが返ってくるか(情報取得が目的の場合)が非常に重要になってくると感じています。

## 外部API連携の流れ
1. APIキーの取得
2. リクエスト、レスポンスの確認
3. リクエスト実装
4. レスポンスの加工

今回の実装ではOpen AIのchatに関してのAPI連携を実施する流れを参考に進めています。

## APIキーの取得
基本的にAPIを介して外部サービスの情報を取得するにはAPIキーの取得がほぼほぼ必要になってくるかなと思います。まずはAPI連携したい外部アプリケーションにAPIキーの発行依頼を行いAPIキーの発行を行いましょう。

## リクエスト、レスポンスの確認
APIキーの発行が済んだらさあ実装だ！！ではなくリクエストとレスポンスの確認を行います。ここをしっかりと事前に確認しておくことで後の実装がスムーズに進みます。

リクエストとレスポンスの確認は簡易的にできるものがよいです。自分は基本的にターミナルでcURLを叩いてて確認しています。

cURLは簡易的にHTTPリクエストとレスポンスを得ることができるものって感じです。

ま、とりあえず叩いて確認してみましょうかね。基本的にAPIに関して公式でドキュメントを発行している企業がほとんどかなと思います。

今回はOpen AIの公式ドキュメントに載ってるcURLコマンドをそのままターミナルで叩いてみましょう。

https://platform.openai.com/docs/api-reference/chat/create

以下のコマンドをご自身のAPIキーに変えて実行してみてください。

```bash
curl https://api.openai.com/v1/chat/completions \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer ご自身のAPIキー(hogehoge)" \
  -d '{
    "model": "gpt-3.5-turbo",
    "messages": [
      {
        "role": "system",
        "content": "You are a helpful assistant."
      },
      {
        "role": "user",
        "content": "Hello!"
      }
    ]
  }'


```

すると以下の画像のようにレスポンスが返ってきました！
レスポンス側に関しては今回Chatの返答を取得する必要があるので``message``の中にある``content``が重要になってきそうですね！

![スクリーンショット 2023-12-02 7.10.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1089852/25fc9317-f103-ac30-4290-297080723bb0.png)

## リクエスト実装
さて、リクエストとレスポンスが確認できたところで実際にリクエスト処理を実装していきたいと思います。

リクエスト処理を実装するために必要なものは主に以下の3点です。
1. ベースとなるURL
2. リクエストヘッダー
3. リクエストボディー

### ベースとなるURL
まずリクエストする際にはベースとなるURLが存在します。今回だとcurlに続く``https://api.openai.com/v1/chat/completions``が該当します。インスタンス変数に格納しておきます。

```ruby:
@base_url = "https://api.openai.com/v1/chat/completions"
```

### リクエストヘッダー
リクエストヘッダーはリクエストに必要なメタデータ(最低限必要な情報?)を組み込む必要があります。
APIキーやCookie情報等。今回はcURLコマンドの``-H``から始まる部分がヘッダー部分に当たるAPIキーの指定とレスポンスの形式をjsonで返す指定をヘッダーに組み込んでいます。
実際の実装では以下の部分でヘッダーをメソッドで定義しています。

```ruby:

def get_api_headers
  {
    "Authorization" => "Bearer #{@api_key}",
    "Content-type" => "application/json",
  }
end
```

### リクエストボディー
リクエストボディーは
今回はcURLコマンドの``-d``から始まる部分のGPTモデルとChat履歴を``message``として渡しています。実際の実装ではそれらに加え``max_tokens``と``temperature``を加え、リクエストボディーを以下で定義しました。

```ruby:

payload = {
  model: "gpt-3.5-turbo",
  messages: @histories,
  #追加オプション
  max_tokens: 512,
  temperature: 0.9,
}
```

ここまででベースとなるURL、リクエストヘッダー、リクエストボディーを定義してきました。あとはベースとなるURLにヘッダーをボディを組み込み、リクエストを投げるだけです。

```ruby:
conn = Faraday.new(url: @base_url) do |faraday|
  faraday.request :json
  faraday.response :json, content_type: /\bjson$/
  faraday.adapter Faraday.default_adapter
end
```
ここでFaradayを使用しベースとなるURLを元にオブジェクトを作成しています。

```ruby:
response = conn.post do |req|
  req.headers = get_api_headers
  req.body = payload.to_json
end
```
そのオブジェクトに対し定義したヘッダー、ボディーを組み込んだものでリクエストし、返ってきた値を``response``変数に格納しています。

## レスポンス実装
リクエストに対して今回は以下のようなjsonでレスポンスが格納されています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1089852/59e414b1-6698-82d5-f49b-8e46d80f729e.png)

あとはここから使用したい値を階層を深掘って取得していきます。今回は

```ruby:
response.body["choices"][0]["message"]["content"]
```
で``Hello! How can I assist you today?``というメッセージを取得することができます。

今回は一つの項目のみ取得しましたが複数の項目を各変数に格納しておいて返却し、それをデータベースにに保存するなり表示するなりするのが一般的なのかなと思います。

## おわりに
いかがだったでしょうか？外部APIを自社システムに導入する際の流れは各々の違うかなと思いますが何となくでも伝われば幸いです。

最後までご覧いただきありがとうございました！
記事を書くモチベーションになりますので少しでも良かったと思っていただけたら左上のいいねボタンポチッといただけますと幸いです。