0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

React開発入門⑤ 〜サーバーサイドAPI通信の実装(Express.js)〜

Last updated at Posted at 2024-11-20

目的

・Expressのインストールおよび起動を行う。
・クライアントからPOSTメソッドを用いてサーバーサイドに情報を渡して処理を行い、クライアント側に返す。
・CORSやAPIを理解する。
・ざっくりと非同期処理を理解する

成果物イメージ

入力フォームの送信をクリックすると入力フォームの情報をPOSTメソッドによるAPI通信でサーバーに受け渡せる。

Express.jsのインストールと起動

/backendなど適当な名前のフォルダを作成してください(reactプロジェクト直下に作るのではなく、分離して下さい。)
作成したフォルダ直下に入り、以下のコマンドを使ってexpressをインストールしてください。

npm install express

フォルダの中に様々なパッケージファイルがインストールされたと思います。

次に、index.jsを記載します。
このindex.jsに
・どのポートで待ち受けるか?
・API用のURLを定義し、どのような処理を行い、レスポンスを行うか?
などを記載します。

今回はテスト用に以下のindex.jsをexpressプロジェクト配下で作成してください。

index.js
const express = require('express');
const app = express();
const port = 3001; // listenするport番号

app.get('/test', (req, res) => {
    res.send("hello world");
});

app.listen(port, () => {
  console.log(`Example app listening on port ${port}`);
});

React(フロント用)で3000番ポートを使用しているため、3001番ポートを使用してください。
ポートがバッティングするとどちらかのアプリケーションが強制停止されてしまいます。

次に以下のコマンドを叩いてexpressサーバーを立ち上げましょう。(index.jsと同じ階層で打ってください)

node index.js

GETメソッドで定義しているため、直接ブラウザ上でURLを叩くとレスポンスが帰ってくるはずです。
ブラウザにlocalhost:3001/testのURLを入力してみましょう。
image.png

しっかりとレスポンスの内容が表示されています。

ログインフォームを作る

まだ、フロント側のログインフォームを作っておりませんのでログインフォームコンポーネントを作成します。
バリデーションのチェックも行う処理も含めて下記のコードになります。(このページに遷移させるルーターも追加してください)

loginForm.jsx
import React, { useState, useRef } from 'react';


export const LoginPage =()=> {
    
    const submitAuthdata = useRef();

    //入力フォームのバリデーションチェックテキスト
    const [usernameText, setUsername] = useState('ユーザー名を入力してください');
    const [passwordText, setPassword] = useState('パスワードを入力してください');

    // =========バリデーションチェック関数=========
    const judgeUsernameValid = (Username) => {
        // 文字列の中に数字が4回以上
        const regexp = /.*\d+.*\d+.*\d+.*\d+/;

        // 文字数が8以上で数字が3つ以上含まれている
        if (8 <= Username.length && Username.match(regexp)) {
            setUsername('入力されたユーザー名はポリシーを満たしています。');
        }
        else {
            setUsername('入力されたユーザー名はポリシーを満たしていません');
        }
        // デバック用
        console.log(Username.length);
        console.log(typeof(Username));
    };
    
    
    // ========バリデーションチェック関数========
    const judgePasswordValid = (Password) => {
        // 文字列の中に数字が4回以上
        const regexp = /.*\d+.*\d+.*\d+.*\d+/;

        // 文字数が8以上で数字がつ以上含まれている
        if (8 <= Password.length && Password.match(regexp)) {
            setPassword('入力されたパスワードはポリシーを満たしています。');
        }
        else {
            setPassword('入力されたパスワードはポリシーを満たしていません');
        }
    };
        
    // ユーザーIDとパスワードのバリデーションチェックがOKなら送信処理を行う。
    const validationCheckText = async (event) => {
        event.preventDefault(); //ページリロード防止

        //バリデーションチェックの可否判定
        if (usernameText=='入力されたユーザー名はポリシーを満たしています。' 
            && passwordText=='入力されたパスワードはポリシーを満たしています。')
            {   
                console.log('フォームの検証成功');
                // 入力フォームの状態を受け取り
                const username = await submitAuthdata.current.querySelector('input');
                console.log(username);
                const password = await submitAuthdata.current.querySelector('input');
                console.log(password);
                
                // json形式のdictを作成
                const jsonString = await {'username': username.value,'password': password.value}
                console.log(jsonString);
                // json.stringify ⇒ dictをjsonオブジェクトに変換
                const userAuthJson = await JSON.stringify(jsonString);
                console.log("userAuthJson");
                console.log(userAuthJson);

                // user認証のAPI
                const url = await 'http://localhost:3001/userauth';
                // ★例外処理は後で書く
                const response = await fetch(url,{
                    method: 'POST',
                    headers: {
                        'Origin': 'http://localhost:3000',
                        'Content-Type': 'application/json',
                    },
                    body: userAuthJson
                })
                const responseJson = await response.json;
                console.log(response);
                console.log(responseJson);
                
                // ページを遷移する処理
                return 'return true';

            }else{

                console.log('フォームの検証失敗');
                return 'return false';
            }
    };

    return(
        <div className='loginForm'>
            <head>
                <meta charset='UTF-8' />
                <title>sample.html</title>
            </head>

            <body>
                <header>
                    <h1>勤怠管理アプリケーション</h1>
                </header>

                <form action='' onSubmit={validationCheckText} ref={submitAuthdata}>
                    <div>
                        Username : <input type='text' name='name' placeholder='username' autoComplete='username'
                                        onChange={(event) => judgeUsernameValid(event.target.value)} 
                                />
                        <p>{ usernameText }</p>
                    </div>
                    <div>
                        Password : <input type='password' name='pass' placeholder='password' autoComplete='current-password'
                                    onChange={(event)=>judgePasswordValid(event.target.value)}
                                />
                        <p>{passwordText}</p>
                    </div>
                    <input type='submit' value='送信' />
                </form>
            </body>
        </div>
        );
    };

image.png
このようにリアルタイムで入力されたユーザー名とパスワードがポリシーを満たしているかを判定しています。
次に、送信ボタンクリックによるFetchAPIを用いたAPI呼び出しについて解説します。

本題

FecthAPIを用いたフロント側でのAPI呼び出し

React側のLoginpage.jsxでサーバーサイドのAPI呼び出し処理をFectAPIを使って書いていきます。

API呼び出しの部分_loginForm.jsx
                // json形式のdictを作成
                const jsonString = await {'username': username.value,'password': password.value}
                console.log(jsonString);
                // json.stringify ⇒ dictをjsonオブジェクトに変換
                const userAuthJson = await JSON.stringify(jsonString);
                console.log("userAuthJson");
                console.log(userAuthJson);

                // user認証のAPI
                const url = await 'http://localhost:3001/userauth';
                // ★例外処理は後で書く
                const response = await fetch(url,{
                    method: 'POST',
                    headers: {
                        'Origin': 'http://localhost:3000',
                        'Content-Type': 'application/json',
                    },
                    body: userAuthJson
                })
                const responseJson = await response.json;

ansyc/await

APIの呼び出しをする際に非同期処理を行う必要があります。

非同期処理...
明示的にこの処理の終了が約束されるまで次の処理が行われないことを保証する

今回は認証情報を確かめるAPIのため、サーバーの応答を待たずに次の処理に進まれると困ります。
非同期を行う関数はaysncで定義し、非同期させたい処理にはawaitを付けることでその処理を終了が確定するまで(正確にはPromiseオブジェクトのresolveが返ってくるまで)待機させてくれます。
他のサイトでもっと詳しく説明されていると思いますので調べてみてください。

json形式

APIでの情報の受け渡しには一般的にJsonというデータ構造を使用します。
Javascriptには標準で辞書型の文字列をJsonデータ構造に変換してくれるJSON.stringifyという関数があります。

json変換_loginForm.jsx
const jsonString = await {'username': username.value,'password': password.value}
const userAuthJson = await JSON.stringify(jsonString);

userAuthJson内にJson形式にされたユーザー名とパスワード情報が格納されています。
これをFetchAPIのhttpボディに入れてサーバーへと送ります。

サーバーサイド側でのJson受け取り

今回はサーバー側でJsonを受け取れるところまで書きます。

index.js
const express = require('express');
const app = express();
const port = 3001; // listenするport番号


//cors対応
var allowCrossDomain = function(req, res, next) {
    res.header('Access-Control-Allow-Origin', 'http://localhost:3000');
    res.header('Access-Control-Allow-Headers', 'X-Requested-With, Origin, X-Csrftoken, Content-Type');
    next();
  }
app.use(allowCrossDomain);

// Body内のJsonを辞書オブジェクトに変換
var bodyParser = require('body-parser');
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());

// POSTのAPI(受け取ったリクエストを表示)
app.post('/userauth', (req, res) => {
  console.log(req.body);
  res.json(
    "{'message': 'OK'}"
);
});

app.listen(port, () => {
  console.log(`Example app listening on port ${port}`);
});

CORS対応

var allowCrossDomain = function(req, res, next) {
    res.header('Access-Control-Allow-Origin', 'http://localhost:3000');
    res.header('Access-Control-Allow-Headers', 'X-Requested-With, Origin, X-Csrftoken, Content-Type');
    next();
  }
app.use(allowCrossDomain);

ここでAPIのレスポンスに'Access-Control-Allow-Origin'ヘッダーを付加しています。
これは別のドメインからAPIを呼び出す時に許可してもよいドメインを指定します。
別のドメインからAPIを呼び出す時に、このヘッダーがないorこのヘッダーのドメインに該当しないAPI問い合わせについては強制的に破棄されてしまいます。
面倒くさいですが、セキュリティ的に仕方ないのでしっかりと許可しても良いドメインを考えてヘッダーを付加しましょう。

テスト:サーバー側で受け取れるか&フロント側にレスポンスが返ってくるか

ログインフォームにポリシーを満たしたユーザー名とパスワードを入力して送信してみましょう。
しっかりとサーバーサイドで受け取れていれば

console.log(req.body);

上のコードによるリクエストのボディがサーバーのログに表示されるはずです。

今回は
ユーザー名:testes12345
パスワード:qiita65535
で試してみます。
また、ブラウザの開発者ツールおよびExpress立ち上げているコンソールで挙動を確かめます。

image.png
送信!

フロント側

ステータスコード200番、つまり成功が返ってきてます。
image.png

### サーバー側
image.png
しっかりとサーバー側のコンソールログ表示で、入力したユーザー名とパスワードの情報が表示されました。
あとはこいつをもとにデータベースに問い合わせたりして色々やっていくわけです。

Next

DB接続とかセッションIDによるログイン状態の管理などをやりたいです。

0
0
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?