【React.js】SpringBootで作成したAPIを呼び出す方法

# はじめに
今回は、SpringBootで作成したRestAPIをReactで呼び出す方法について解説します。

SpringBootにReactを導入する方法を調べても、思ったようなものを見つけられなかったので備忘録として残しておきます。

# 前提
- SpringBootでアプリケーションが作成されていること

# バックエンド(API)側の実装
まずは、バックエンドの実装をします。
ここでは、Springスターター・プロジェクトを作成して、レスポンスを返すところまでを実装します。

## SpringBootプロジェクトの作成
プロジェクトの作成ですが、ビルドツールとしては`Gradle`を選択し、依存関係として以下を選択します。
- Spring Web
- Lombok
- SpringBoot Devtools

最低限アプリケーションが動作すればいいので、上記3つのみ選択します。(もちろん、がっつりアプリケーションを開発する場合は、これ以外にも選択する必要があります)

## Controllerの実装
先ほど、記述したように、今回は必要性低減の実装のためControllerのみ作成します。
(ここでも上記同様の追加説明ですが、がっつりアプリケーションを開発する場合は、ServiceクラスやMapperが必要です)

実際のソースは以下になります。

```java:HelloController.java
package com.example.demo.app.controller;

import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

import com.example.demo.domain.entity.BirthStone;

@RestController
@CrossOrigin(origins = "*") 
public class HelloController {
	
    @GetMapping("/api")
    @ResponseBody
    public BirthStone getBirthStone() {
        BirthStone birthStone = new BirthStone();
        birthStone.setMonth("2月");
        birthStone.setName("アメジスト");
        birthStone.setColor("紫");
        return birthStone;
    }
}
```

ポイントを解説すると、まずは`@RestController`アノテーションを付与して、RestAPI用のレスポンスを返却するようにし、APIサーバー用のコントローラーとします。

次に`@CrossOrigin(origins = '*')`アノテーションです。
実際に、このAPIをフロント側で呼んだ時に、このアノテーションがないと以下のエラーがコンソールに出力されます。

**「クロスオリジン要求をブロックしました: 同一生成元ポリシーにより、【※APIのURL】 にあるリモートリソースの読み込みは拒否されます (理由: CORS ヘッダー ‘Access-Control-Allow-Origin’ が足りない)。[詳細]」**

簡単に言うとこのエラーは、「**CORS**(**オリジン間リソース共有**)の制御ができていない」というエラーです。
> [オリジン間リソース共有(CORS)](https://developer.mozilla.org/ja/docs/Web/HTTP/CORS)

そのため、`@CrossOrigin`アノテーションを付与し、CORSを制御します。
引数の`origins`(Access-Control-Allow-Originの設定)は'＊'(ワイルドカード)を設定します。
このように記述することでリクエストで許可するオリジンを設定できます。

ここで、そもそもオリジンとは・・・という人に向けて↓
> HTTP通信における「オリジン」（origin：データの送信元）とは、Webページや画像ファイルなどの所在を表すURLのうち、URIスキーム（'http://'か'https://'かの違い）、ホスト名（Webサーバのドメイン名）、ポート番号（デフォルトではhttpがTCP80番、httpsがTCP443番）の組み合わせのこと

また、メソッドに`@ResponseBody`アノテーションを付与することで、戻り値をそのままレスポンスのコンテンツにすることができます。

このようにすることでRestAPIのレスポンスを返却する動作を実装できます。

ちなみに、Entityは以下のようになっています。
```java:BirthStone.java
package com.example.demo.domain.entity;

import java.io.Serializable;

import lombok.Data;

@Data
public class BirthStone implements Serializable {

    private static final long serialVersionUID = 1L;

    /** 月 */
    private String month;

    /** 名前 */
    private String name;

    /** 色 */
    private String color;

}
```

ここまで実装できたら、アプリケーションを起動しリクエストしてみましょう。
以下のような、JSON形式のレスポンスが返却されるはずです。
(APIの場合、curlコマンドでリクエストをします)

■リクエスト手順
① `curl http://localhost:8080/api`をターミナルで叩く
② レスポンスを確認する(以下が返却される)
```
{"month":"2月","name":"アメジスト","color":"紫"}
```


# フロント(React.js)側の実装
フロント側の実装では、Reactアプリケーションの作成(Create React Appを行う)から、実際にRestAPIの呼び出しを行うところまでを実装します。

## Create React App
まずは、Reactアプリケーションを作成します。
作成する場所は、どこでもいいですが、プロジェクトの括りは同じにするべきかと思うので、SpringBootプロジェクトと同様の階層に作成します(以下、参照)。
```
プロジェクト名
├─ ReactApp
│  ├─ src
│  ├─ node_modules
│  ├─ package.json
│  └─ etc...
├─ src
│  ├─ main
│  └─ test
├─ build.gradle
└─ etc...
```

手順としては、以下のように行います。

① ターミナルでSpringBootプロジェクトのある階層まで移動する
② 以下のコマンドでReactアプリケーションを作成する
③ アプリケーションを起動する

```terminal
npx create-react-app アプリケーション名
```

無事、アプリケーションが作成できたら以下コマンドでアプリケーションを起動してみましょう。
```terminal
cd アプリケーション名

npm start
```
初期画面が表示されていたら、成功です。

## APIを呼び出すための実装
いよいよ、作成したAPIを呼び出していきます。
まずは、proxyの設定を行います。
### ①proxyの設定

proxyの設定ですが、`package.json`に以下を追加します。

```react:package.json
"proxy": "http://localhost:8080"
```
プロキシにAPI側のURLを設定することで、APIと接続することができます。
逆に言えば、この設定がないと、APIを叩いてデータを引っ張ってくることができないということです。

記述場所は、任意ですが`scripts`の下に記述するといいかと思います。

### ②APIをfetchする(呼び出す)コンポーネントの作成
src配下にcomponentsディレクトリを作成し、コンポーネントファイルを作成します。(以下、参照)
```
ReactApp
├─ src
    ├─ components
            ├─ ApiFetch.jsx
```
作成したら、APIをfetchするための実装を行います。

```react:ApiFetch.jsx
import React, { useState, useEffect } from "react";

export const ApiFetch = () => {
	const [stones, setStone] = useState([]);

	useEffect(() => {
		// APIをfetchする(呼び出す)
		fetch("http://localhost:8080/api", { method: "GET" })
			// レスポンスのデータ形式をjsonに設定
			.then((res) => res.json())
			// APIから渡されるレスポンスデータ(data)をstateにセットする
			.then((data) => {
				setStone(data);
			});
	}, []);

	return (
		<div>
			<ul>
				<li>{stones.month}</li>
				<li>{stones.color}</li>
				<li>{stones.name}</li>
			</ul>
		</div>
	);
};
```
※ 解説はコメントに記載しているので、そちらを参照してください。

上記の実装が完了したら、コンポーネントの要素を描画していきます。
### ③コンポーネントの描画
`App.js`か`index.js`のどちらでもいいですが、コンポーネントを差し込んでいきます。
(自分の場合は、コンポーネント部分がわかりやすくなるようindex.jsに描画しました)
```index.js
import React from "react";
import ReactDOM from "react-dom/client";
import "./index.css";
import App from "./App";
import reportWebVitals from "./reportWebVitals";
import { ApiFetch } from "./components/ApiFetch"; //追加

const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
	<React.StrictMode>
		<App />
		<ApiFetch /> // 追加
	</React.StrictMode>
);
```

これでコンポーネントの差し込みが完了しました。
`npm start`をして`localhost:3000`にアクセスすると、以下のようにAPIのデータが描画されているかと思います。

このようにすることでReactからAPIを叩くことができます。

![5658f59a5e68c8fda05760811e48ae97.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/879778/ed0473a6-379f-ca63-35e4-f9deef0433b5.png)

# 参考文献
> [【React】fetchメソッドでREST APIを叩く方法](https://omathin.com/react-api-2/)
>
> [◆ Spring Bootで作成したAPIをReactからGETする](https://qiita.com/Haru_3/items/d1644226682dfbc3a9a3)
>
> [【Spring Boot】CORSの設定](https://b1san-blog.com/post/spring/spring-cors/)
>
> [CORS 【Cross-Origin Resource Sharing】](https://e-words.jp/w/CORS.html#:~:text=HTTP%E9%80%9A%E4%BF%A1%E3%81%AB%E3%81%8A%E3%81%91%E3%82%8B%E3%80%8C%E3%82%AA%E3%83%AA%E3%82%B8%E3%83%B3%E3%80%8D%EF%BC%88,%E7%95%AA%EF%BC%89%E3%81%AE%E7%B5%84%E3%81%BF%E5%90%88%E3%82%8F%E3%81%9B%E3%81%AE%E3%81%93%E3%81%A8)