React✖️AxiosでAPIにリクエストを送信しHelloWorldを表示する

SpringBoot3(REST API)✖️ReactJSで作るSNS風Webアプリケーション

今パートの目標

前回はリクエストを送ると「HelloWorld」というテキストをレスポンスとして返すHelloControllerの作成をしました。
今回はReactとAxiosを使用してAPIで作成したHelloControllerに向けてリクエストを送信し、取得した結果を画面に表示していきたいと思います。

環境について

  • react 18.2.0
  • Typescript 4.9.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データの自動変換も行ってくれるためレスポンスデータの処理がしやすくなっています。

Getting Started | Axios Docs

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設定には複数の方法があります。
詳細についは以下の記事を参照してください。

【Spring Boot】CORSの設定
CORSについてとSpring BootにおけるCORSの設定方法について説明します。

公式

Spring Boot REST API で CORS を有効化 - 公式サンプルコード
Spring Boot の概要から各機能の詳細までが網羅された公式リファレンスドキュメントです。開発者が最初に読むべきドキュメントです。

今回は設定用のクラスを作成し、設定していく方法を取りたいと思います。

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サイトをだれでも見れる状態にしていきたいと思います。

Cloud Application Hosting for Developers | Render
Render is a unified cloud to build and run all your apps and websites with free TLS certificates, global CDN, private ne...
余談

Herokuを愛用していたのですが、無料プランが廃止となってしまったため無料で利用できるRenderを使用した環境構築に挑戦してみたいと思います。

コメント

タイトルとURLをコピーしました