Rails✖️Next.js cors axiosを使って単純なデータの取得

初学者で初めてAPI通信にて、ポートフォリオを作成しています。

バックエンドとフロントにて別アプリで作成するためのAPI通信が全くわからず、
とりあえずJsonでHelloと渡す簡単なデータの取得ができたので、メモとして残します。

間違った認識や書き方、アドバイスがあれば教えてもらえると嬉しいです。

## 開発環境
dockerを使用。
docker-composeにて、rails,Next.jsを管理。

**Next.js(フロントエンド)**
 "next": "13.3.0",　"react": "18.2.0",
オリジン "http://localhost:8080"

**rails(バックエンド)**
ruby '3.1.4','rails', '~> 6.1.7', '>= 6.1.7.3'
オリジン "http://localhost:3000"


## 手順

⚪︎rails

1. json形式"Hello"データを渡す、routesの設定。
1. gem 'rack-cors'を追加。
1. config/initializers/cors.rbにて、corsの設定。

⚪︎Next.js

1. axiosを追加。
1. axiosにてbaseURLを指定する。
1. APIエンドポイントにGETリクエストを送信する関数
1. コンポーネントのマウント時にAPIリクエストを送信。
1. 取得したデータを表示

## Rails
### 1. json形式データを渡す。
```ruby:hello_controller.rb
class Api::V1::HelloController < ApplicationController
  def index
    render json: "hello"
  end
end
```
```ruby:routes.rb
Rails.application.routes.draw do
  namespace :api do
    namespace :v1 do
      get 'hello', to: 'hello#index'
    end
  end
end
```

※参考
[　API（非同期通信を実装する場合）](https://qiita.com/kusaharajiji/items/3b374c73c12233485feb "API（非同期通信を実装する場合）")

### ２. gem 'rack-cors'を追加。
コメントになっているので、コメントを解除する。
```diff_ruby:Gemfile
# Use Rack CORS for handling Cross-Origin Resource Sharing (CORS), making cross-origin AJAX possible
- # gem 'rack-cors'
+ gem 'rack-cors'
```

Gemfileを更新した際は、buildとbundle install忘れずに！

```terminal
$ docker-compose build --no-cache

$ docker-compose run --rm (サービス名) bundle install
```

### 3. config/initializers/cors.rbにて、corsの設定。
CORS（Cross-Origin Resource Sharing）の設定にて、異なるオリジン（ドメイン・ポート・プロトコルの組み合わせ）からのリクエストを許可する設定を記述。

```rails:cors.rb
Rails.application.config.middleware.insert_before 0, Rack::Cors do
  allow do
# 許可するオリジンの設定
    origins 'localhost:8080'
# 全てのリソースに対してCORS設定を適用。
    resource '*',
# :anyで全てのリクエストヘッダーを許可する。
      headers: :any,
# 許可するHTTPメソッド（GET、POST、PUT、PATCH、DELETE、OPTIONS、HEAD）を指定。
      methods: [:get, :post, :put, :patch, :delete, :options, :head]
  end
end
```

・リクエストヘッダー(Request Header)
HTTPリクエストに関する、様々なメタ情報を提供し、サーバーがリクエストを処理する情報を提供する。

※参考
[基本的なWeb技術に関するまとめ](https://qiita.com/gensan64311466/items/d76f7fbd391521eb20a8 "基本的なWeb技術に関するまとめ")
[axiosとrailsのCORS](https://qiita.com/YokoYokoko/items/68b4abd3e406f41da3b2 "axiosとrailsのCORS")


## ⚪︎Next.js
### 1. axiosを追加。
```terminal
$ docker-compose rum --rm <サービス名> npm install axios
```

### 2. axiosのインスタンスを作成。
実際のポートフォリオでは、beseURLをaxiosのインスタンスで作成し、
別ファイルに書いてインスタンスをエクスポートします。

今回はシンプルにindex.jsに全て書いてしまいます。
```react:index.js
import axios from "axios";

export default function Hello() {

// Axiosインスタンスを作成して、複数のエンドポイントを設定可能にする。
// baseURLを設定する。
  const instance = axios.create({
    baseURL: "http://localhost:3000",
  });

// APIエンドポイントURL(実際railsからHelloを取得するためのURL)
  const apiUrl = "/api/v1/hello";
```
### 3. axiosインスタンスを利用し、実際のURLにgetリクエストを送信する関数を作成。
```react:index.js
// useStateを使用するので、追加
import { useState } from "react";

~~~~~~~~~~~~~~~
省略
~~~~~~~~~~~~~~~
// 取得したデータを、表示するためにuseStateを使用
  const [helloData, setHelloData] = useState("");

// async関数で非同期関数として作成
// getリクエストを送り、データを取得する関数。
  const getHello = async () => {
// 非同期関数内では、APIリクエストも非同期に行うため'try-eatch'文を使用
// 非同期処理成功は、'try'ブロック内のコードが実行
// エラーが発生した場合は、'catch'ブロックが実行され、エラーが'error'に格納される
    try {
// 'instance.get(apiUrl);':'axios.get(apiUrl)'
// awaitは非同期操作を同期的に扱っているため、'axios.get(apiUrl)'が完了するまで次のコードが実行されません。
// 'axios.get(apiUrl)'は、getリクエストを送信し、サーバーからのレスポンスを取得
      const response = await instance.get(apiUrl);
      setHelloData(response.data);
    } catch (error) {
      console.error(error);
    }
  };
```

### 4. コンポーネントのマウント時にAPIリクエストを送信。
```react:index.js
// コンポーネントがマウント時に一度だけ実行される。
  useEffect(() => {
    getHello();
  }, []);
```
### 5. 取得したデータを表示
```diff_javascript:index.js
import { useState, useEffect } from "react";
import axios from "axios";

export default function Hello() {
  const instance = axios.create({
    baseURL: "http://localhost:3000",
  });
  // APIエンドポイントのURL
  const apiUrl = "/api/v1/hello"; // 実際のURLに置き換えてください

  const [helloData, setHelloData] = useState("");

  // APIエンドポイントにGETリクエストを送信する関数
  const getHello = async () => {
    try {
      const response = await instance.get(apiUrl);
      setHelloData(response.data);
    } catch (error) {
      console.error(error);
    }
  };
  // コンポーネントのマウント時にAPIリクエストを送信
  useEffect(() => {
    getHello();
  }, []);

  return (
+   <div>
+     <h1>Response: {helloData}</h1>
+   </div>
  );
}
```

※参照
[axiosとrailsのCORS](https://qiita.com/YokoYokoko/items/68b4abd3e406f41da3b2 "axiosとrailsのCORS")

非同期処理やAPIについては以下をとても参考にしました。
[WebAPIについての説明](https://qiita.com/busyoumono99/items/9b5ffd35dd521bafce47 "WebAPIについての説明")

何となくの雰囲気がわかるように、参考になると嬉しいです。

また、間違っている部分などあればご指摘いただけると嬉しいですし、
これ勉強したほうがいいよ！とかも教えてもらえると嬉しいです。