今パートの目標
前回はリクエストを送ると「HelloWorld」というテキストをレスポンスとして返すHelloControllerの作成をしました。
今回はReactとAxiosを使用してAPIで作成したHelloControllerに向けてリクエストを送信し、取得した結果を画面に表示していきたいと思います。
環境について
- Next.js 14.2.3
- Typescript 5
- SpringBoot 3.2.0
- java 17
- git 2.43.0
- macOS Sonoma 14.1.1
- Docker Desktop 4.18.0
作業用ブランチを作成する
下記コマンドを実行し、作業用ブランチを作成します。
share-favplace-front % git fetch
share-favplace-front % git checkout -b develop
share-favplace-front % git checkout -b develop_20231225_requestAPI
Axiosをインストールする
下記コマンドを実行し、Axiosをインストールします。
share-favplace-front % docker-compose run --rm front npm install axios
AxiosとはHTTPクライアントライブラリです。PromiseベースのAPIを提供しているので非同期処理が扱いやすく、JSONデータの自動変換も行ってくれるためレスポンスデータの処理がしやすくなっています。
Axiosのconfigファイルを作成する
axiosのグローバル設定を行うための設定ファイルを作成します。
share-favplace-front % mkdir ./src/configs
share-favplace-front % touch ./src/configs/axios.ts
axios.tsを編集する
import axios from "axios";
let instance = axios.create({
baseURL: process.env.REACT_APP_API_URL,
});
// 本番環境以外はリクエストとレスポンス時にデバッグ用ログを出力する
if (process.env.REACT_APP_ENV !== 'production') {
instance.interceptors.request.use(
(config) => {
console.log(config);
return config;
},
(error) => {
console.log(error);
return Promise.reject(error);
}
);
instance.interceptors.response.use(
(response) => {
console.log(response);
return response;
},
(error) => {
console.log(error);
return Promise.reject(error);
}
);
}
export default instance;
コードを説明していきます
let instance = axios.create({
baseURL: process.env.REACT_APP_API_URL,
});
baseURL(APIのURL)を設定しています。
環境によって変更したいため、”REACT_APP_API_URL”という環境変数を参照するように記述します。環境変数は後で登録します。
開発環境では”http://loclahost:8080″がここに入ります。
REACT_APP_{変数名}という環境変数名で登録するとReactアプリからprocess.env.{環境変数名}で環境変数を取得することができます。
// 本番環境以外はリクエストとレスポンス時にデバッグ用ログを出力する
if (process.env.REACT_APP_ENV !== 'production') {
instance.interceptors.request.use(
(config) => {
console.log(config);
return config;
},
(error) => {
console.log(error);
return Promise.reject(error);
}
);
instance.interceptors.response.use(
(response) => {
console.log(response);
return response;
},
(error) => {
console.log(error);
return Promise.reject(error);
}
);
}
“REACT_APP_ENV”という環境変数を登録し、本番環境以外はデバッグログを出力するようにしています。
instance.interceptors.request.use()
リクエスト送信時に実行したい処理を記述します。
instance.interceptors.response.use()
レスポンス受け取り時に実行したい処理を記述します。
これを使用して共通エラーハンドリング処理を作成することなどもできます。
環境変数を登録する
axios.tsで参照する環境変数を登録します。
react-app-variables.envを作成する
下記コマンドを実行し、envファイルを作成します。
share-favplace-front % mkdir environment
share-favplace-front % touch environment/react-app-variables.env
react-app-variables.envを編集する
# react
REACT_APP_ENV=development
REACT_APP_API_URL=http://localhost:8080/
envファイルはgithubにあげる必要は無いので.gitignoreに追記しておきましょう
*.env
docker-compose.ymlを編集する
version: "3.9"
services:
front:
build:
context: .
args:
WORKDIR: ${WORKDIR}
container_name: share-favplace-front
env_file:
- ./environment/react-app-variables.env
command: npm run start
volumes:
- .:/${WORKDIR}
ports:
- "${FRONT_PORT}:${FRONT_PORT}"
環境変数ファイルを登録するように変更します。
APIにリクエストを送信する
FrontのReactアプリからAPIに向けてHttpリクエストを送信していきます。
App.tsxを編集する
App.tsxでボタンを押下するとリクエストを送信するように編集していきましょう
import { useState } from 'react';
import axios from './configs/axios';
export default function App() {
const [text, setText] = useState('');
const handleClick = () => {
axios.get('/api/v1/hello')
.then((res) => {
setText(res.data)
})
};
return (
<div>
<div className='flex justify-center mt-10'>
<button type="button" className="text-white bg-gradient-to-r from-purple-500 to-pink-500 hover:bg-gradient-to-l focus:ring-4 focus:outline-none focus:ring-purple-200 dark:focus:ring-purple-800 font-medium rounded-lg text-sm px-5 py-2.5 text-center me-2 mb-2" onClick={() => handleClick()}>Click!</button>
</div>
<div className="flex justify-center mt-5">
<h1 className="text-3xl font-bold underline">
{ text }
</h1>
</div>
</div>
)
}
下記のような画面になります。
少しコードの説明をします
<button ... onClick={() => handleClick()}>Click!</button>
ボタンのクリック操作時にhandleClick()というメソッドを実行するという意味になります
const handleClick = () => {
axios.get('/api/v1/hello')
.then((res) => {
setText(res.data)
})
};
axiosを使用して’/api/v1/hello’にリクエストを送信し、レスポンスをtext変数にセットします。
axiosの設定ファイルでbaseURLを設定しているのでhttp://localhost:8080/api/v1/hello にリクエストを送信します。
const [text, setText] = useState('');
useState(”)により、変数の状態を管理します。
これによって、変数に値が代入された際に画面の表示を適切に変更することができます。
Reactのhooksについては以下動画がとても分かりやすいのでReactを触る前に一度視聴することをお勧めします。
<h1 className="text-3xl font-bold underline">
{ text }
</h1>
ここにレスポンスで取得したtextを表示します。
リクエストを送信する
Click!ボタンを押してリクエストを送信してみましょう
しかし今のままでは画像の通り、エラーとなってしまいます
重要なのはこのエラーメッセージです。
Access to XMLHttpRequest at 'http://localhost:8080/api/v1/hello' from origin 'http://localhost:3000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
上記より、CORSエラーとなっていることが分かります。
SpringBoot3のCORS設定
SpringBootのCORS設定をしていきます。
CORSとは
CORSとはCross-Origin Resource Sharingの略で、「オリジン間リソース共有」という意味です。
つまりあるオリジンで動いている Web アプリケーションに対して、別のオリジンのサーバーへのアクセスをオリジン間 HTTP リクエストによって許可できる仕組みのことです。
今回の場合はフロントエンドとバックエンドで異なるオリジンとなっているため、アクセスを許可する設定をしてあげる必要があります。
バックエンドで設定するのが一般的なため、SpringBootの機能を使って設定していきます。
Origin(オリジン)とは
protocol(プロトコル) + domain(ドメイン) + port number(ポート番号)のことです。
上記3つの項目が全て一致していないと異なるオリジンとなります。
今回の場合は開発環境の各オリジンは以下のようになるため、CORSの設定が必要となります。
※本番環境でも異なります。
- フロントエンド
http://localhost:3000 - バックエンド
http://localhost:8080
CORSの設定
CORS設定をしていきます。
SpringBootのCORS設定には複数の方法があります。
詳細についは以下の記事を参照してください。
公式
今回は設定用のクラスを作成し、設定していく方法を取りたいと思います。
configパッケージを作成する
以下階層にconfigパッケージを作成します。
src
└ main
└ java
└ {パッケージ名}
└ config
WebMvcConfigクラスを作成する
先ほど作成したconfigパッケージにWebMvcConfig.javaを作成しまず
src
└ main
└ java
└ {パッケージ名}
└ config
└ WebMvcConfig.java
WebMvcConfig.javaを編集する
package com.pandaman.sharefavplaceapi.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
final String origin = System.getenv("FRONT_URL");
registry.addMapping("/**")
.allowedOrigins(origin)
.allowedMethods(CorsConfiguration.ALL);
}
}
コードについて説明していきます
@Configuration
設定クラスであることを表します。このアノテーションを付与することでSpringBootが実行時に参照して設定をしてくれます。
@Override
実装しているWebMvcConfigurerインターフェースに定義されたメソッドをオーバーライドしていることを表します。
addCorsMappings(CorsRegistry registry)
このメソッドを実装し、引数のregistryに設定を追加していくことでCORSの設定をしていきます。
addMapping(“/**”)
CORS の対象となるパスを設定します。今回は全てのパスを設定しています。
allowedOrigins(String… origins)
許可するオリジン(Access-Control-Allow-Origin)を設定します。
今回はFRONT_URL(http://localhost:3000)を設定しています。
allowedMethods(String… methods)
許可するHttpリクエストメソッド(Access-Control-Allow-Methods)を設定します。
今回はCorsConfiguration.ALL(*)全てのリクエストメソッドを設定しています。
※HttpリクエストメソッドとはGetやPost、Delete等のことです。
以上で設定は完了です。SpringBootは再起動しておきましょう。
リクエストを送信する
それではもう一度Click!ボタンを押してリクエストを送信してみましょう
無事APIからHelloWorld!!!!を取得して画面に表示することができました。
githubにプッシュする
作成したソースコードをgithubにプッシュしておきましょう。
フロントエンド
share-favplace-front % git add -A .
share-favplace-front % git commit -m "axiosとAPIへのリクエスト送信処理追加"
share-favplace-front % git push origin develop_20231225_requestAPI
バックエンド
share-favplace-api % git add -A .
share-favplace-api % git commit -m "Helloworldを返すAPIの実装追加"
share-favplace-api % git push origin develop_20231226_responseToFront
developブランチにマージする
githubにpushできたら、プルリクエストを作成し、developブランチに変更をマージしていきます。
プルリクエストを作成する
GitHubにPUSHした後にログインし、リポジトリのページに行くとアラートが出ているので「Compare&PullRequest」を押下しプルリクエストを作成します。
対象ブランチを「develop←develop_20231225_requestAPI」に変更し、差分を確認します。
差分に問題がなければ、「Create pull request」を押下し、プルリクエストを作成します。
developブランチにマージする
先ほど作成したプルリクエスト画面から「Merge pull request」を押下し、変更をマージします。
上記をフロントエンドバックエンドともに行ったら完了です。
おまけ
なぜわざわざプルリクエストを作成するのか
個人開発では特に意味のない無駄な作業に思えるプルリクエストですが、
実務ではプルリクエストを作成して別の人にコードレビューをしてもらい、問題がなければマージするというような流れをとるのが一般的だと思います。
なので、実務に沿った開発を個人開発でもしている方が、チーム開発でもGitHubを扱えるというアピールにもなるかなと思い、僕はそのようにしています。
まとめ
以上でaxiosを使用して、API側にリクエストを送信し、HelloWorld!!!!を表示するところまでできました!
ここまでできればあとは自分で作りたいアプリに合わせて機能を追加していくだけです😊
次回はRenderを使って本番環境を構築し、作成したWebサイトをだれでも見れる状態にしていきたいと思います。
余談
Herokuを愛用していたのですが、無料プランが廃止となってしまったため無料で利用できるRenderを使用した環境構築に挑戦してみたいと思います。
コメント