React axios RailsAPIを叩いてみる

今回は、ハッカソン形式のインターンでAxiosを使って
Rails APIを叩く機会があったので、その備忘録です！
（少し解説あります！）

# 内容
1. Axiosとは
1. 実際に書いてみた


# Axiosとは
簡単に言うと、APIをサクッと叩いてくれる便利なやつです。
APIを利用するときに、**このパスをGETのメソッドで送ってね**とか
あるのですが、この説明通りに実装できるのがAxiosです。

厳密にはHTTP通信、Promiseの云々カンヌンありますが
気になる人は、[公式サイト](https://axios-http.com/docs/intro)を見てみたり、JS自体を勉強したりしてみましょう〜


今回は、解説＆コード全部載せてるので
コードだけ欲しいよ！という人は「コードの全容」に飛んでくださいね！

# 解説
## 導入手順
導入手順は以下のように進めます。
1. `npm` or `yarn`でaxiosをインストール
1. インポート（自分のファイルで使えるようにする）
1. 基本的な設定を作る
1. 便利な関数を作成する

### 1. `npm` or `yarn`でaxiosをインストール
ターミナルで以下のコマンドを実行します。
```zsh:ターミナル
% npm i axios
```
他の様式でのインストール方法は↓に載ってます！

https://axios-http.com/docs/intro

### 2. インポート（自分のファイルで使えるようにする）
axiosをインポートし、自分のファイルの中で使えるようにします
```ts
import axios from 'axios'
```


### 3. 基本的な設定を作る
```ts
const DEFAULT_API_CONFIG = {
  baseURL: 'http://0.0.0.0:4000/api/v1',
  timeout: 5000,
  mode: 'cors',
  credentials: 'include',
  headers: {
    ContentType: 'application/json',
    Accept: 'application/json',
  },
}
```
- `baseUrl`は、APIを叩く上で、ほぼ毎回叩くURL（固定のようなもの）を指定します。
- `timeout`は通信関連ですが、特に通信の制約があるとかない場合は無視でOKです！
- `mode`は`cors`(Cross-Origin Resource Sharering)を指定します。
    - corsはクライアントが自分と違うオリジンをもつサーバーからデータを取得する仕組みのこと
    - RailsのAPI側で予め仕込む必要があります
- `credentials`はincludeですが、特に気にしなくていいです
- `headers`は、HTTP通信で送るヘッダー部分です。
    - 今回はRailsでJSONを返すので、`json`としています

こんな感じで色々設定します！
もう少し知りたい方は↓です！

https://axios-http.com/docs/config_defaults

### 4. 便利な関数を作成する
#### 4-1. Axiosのインスタンスを作る関数
```ts
const newAxiosInstance = () => {
  const instance = axios.create(DEFAULT_API_CONFIG)

  instance.interceptors.response.use(
    (response) => {
      if (process.env.NODE_ENV === 'development') {
        console.log(response)
      }
      return response
    },
    (error) => {
      return Promise.reject(error)
    },
  )

  return instance
}
```
まず、GET、POSTのメソッドでAPIを叩くにしても
Axiosの仕様的に、インスタンスを作っておく方が便利そうです。
（作らない場合は、少しコードが伸びるので😅）

また、`interceptors`では、リクエストやレスポンスが
`then`や`catch`で処理される前にもらえるデータの設定をすることができます。

Interceptorsについて知りたい方は↓です！

https://axios-http.com/docs/interceptors


#### 4-2. インスタンスを利用したGETでAPIを叩く関数
```ts
export const getAPIData = async (path: string) => {
  const instance = newAxiosInstance()
  try {
    const response = await instance.get(path)
    return response
  } catch (error: any) {
    return error.response
  }
}
```
ここでは、先ほど作成したインスタンスを作る関数を利用しています。
APIを叩くときは非同期処理なので、関数自体に`async`、実際に非同期処理になる
ところの前に`await`をつけます。

Axiosでは、`instance`のメソッドで`get`,`post`を指定できるので、
今回は`get`を指定します。

この関数では、BaseUrlの後ろに続くURLのパスを入れるだけでGETメソッドで
APIを叩いてくれます。これでAxios？？ってなる人でも簡単に使えますね〜！

#### 4-3. インスタンスを利用したPOSTでAPIを叩く関数
```ts
export const postAPIData = async (path: string, params: object) => {
    const instance = newAxiosInstance()
    try {
        const response = await instance.post(path, params)
        return response
    } catch(error: any) {
        return error.response
    }
}
```
ここでも先ほど作成したインスタンスを作る関数を利用しています。
大体GETの関数と同じですが、`params`を渡す点が異なります。
POSTでは、データをAPIに送る役割があり、大体DB内のIDを使って
取得するものや、DBに登録する際に使います。
その時に必要な情報を`params`に入れて、送ります。

この関数では、先ほどのGETの関数と同じパスに加え
POSTとして必要な情報を引数に渡すだけでPOSTできちゃいますね！
（関数名が微妙なのはスルーで😇）

# コードの全容
完成版は↓↓↓です！
```ts:axiosUtl.ts
import axios from 'axios'

const DEFAULT_API_CONFIG = {
  baseURL: 'http://0.0.0.0:4000/api/v1',
  timeout: 5000,
  mode: 'cors',
  credentials: 'include',
  headers: {
    ContentType: 'application/json',
    Accept: 'application/json',
  },
}

const newAxiosInstance = () => {
  const instance = axios.create(DEFAULT_API_CONFIG)

  instance.interceptors.response.use(
    (response) => {
      if (process.env.NODE_ENV === 'development') {
        console.log(response)
      }
      return response
    },
    (error) => {
      return Promise.reject(error)
    },
  )

  return instance
}

export const getAPIData = async (path: string) => {
  const instance = newAxiosInstance()
  try {
    const response = await instance.get(path)
    return response
  } catch (error: any) {
    return error.response
  }
}

export const postAPIData = async (path: string, params: object) => {
    const instance = newAxiosInstance()
    try {
        const response = await instance.post(path, params)
        return response
    } catch(error: any) {
        return error.response
    }
}
```
exportのおかげでimportするだけで色んなファイルの中で使えて
毎回毎回別のコンポーネントで定義しなくていいので
少し楽になりますね！

今回は以上になります！
若干メモ感ありますが、気になる方は以下の公式を見てみてください🌸

https://axios-http.com/docs/intro