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?

Expressでjoiを使ってバリデーションを実装する

Last updated at Posted at 2024-10-02

前回の記事では、Reactでバリデーションを実装してみました。

今回は、バックエンドでExpressにおいてJoiライブラリを使ったバリデーションの実装をしてみたいと思います。

Joiライブラリの基本的な使い方

Joiライブラリは、データのバリデーションを簡単かつ強力に行うことができるツールです。
Joiのドキュメントを参照して、基本的な使い方を見てみます。

まず、Joiライブラリを下記コマンドでインストールします。

npm i joi

下記コードを作成します。

index.js
const Joi = require('joi')

const schema = Joi.object({
  name: Joi.string().required(),
  age: Joi.number().min(0),
  location: Joi.string()
})

const { value, error } = schema.validate({name: '鈴木', age: 12, location: '大阪'})
console.log("value: ", value)
console.log("error: ", error)

ここでは、Joiのオブジェクトschemaを定義し、schemaにはname, age, locationという三つのプロパティがあります。nameプロパティは文字列型(string)、かつ省略不可(required)である。ageプロパティは数字(number)で、かつ0以上でなければならない(min(0))。locationプロパティは文字列型(string)である。ドキュメントを見ると、ほかにもたくさんの型や数字の範囲を限定するメソッドがあります。これらがバリデーションチェックを楽にしてくれます。
さらにvalidateメソッドを用いて、引数にオブジェクトを代入し、結果を返します。

このコードを実行すると、下記出力になります。

value:  { name: '鈴木', age: 12, location: '大阪' }
error:  undefined

この結果からわかる通り、valueには引数で代入したオブジェクトが格納されています。また、入力したオブジェクトはすべて条件を満たしている為エラーも発生していないようです。

次に、schemanameプロパティにはrequiredageプロパティにはmin(0)がそれぞれ指定されていますので、nameプロパティを省略した場合とageプロパティを負の値にした場合をそれぞれ試してみましょう。

nameプロパティを省略した場合

index.js
const Joi = require('joi')

const schema = Joi.object({
  name: Joi.string().required(),
  age: Joi.number().min(0),
  location: Joi.string()
})

const { value, error } = schema.validate({ age: 12, location: '大阪' })
console.log("value: ", value)
console.log("error: ", error)

これを実行すると、下記結果が出力されました。

value:  { age: 12, location: '大阪' }
error:  [Error [ValidationError]: "name" is required] {
  _original: { age: 12, location: '大阪' },
  details: [
    {
      message: '"name" is required',
      path: [Array],
      type: 'any.required',
      context: [Object]
    }
  ]
}

想定通りError [ValidationError]: "name" is requiredというエラーが出ました。

ageプロパティを負の値にした場合

index.js
const Joi = require('joi')

const schema = Joi.object({
  name: Joi.string().required(),
  age: Joi.number().min(0),
  location: Joi.string()
})

const { value, error } = schema.validate({ name: '鈴木', age: -12, location: '大阪' })
console.log("value: ", value)
console.log("error: ", error)

これを実行すると下記結果が出力されました。

value:  { name: '鈴木', age: -12, location: '大阪' }
error:  [Error [ValidationError]: "age" must be greater than or equal to 0] {
  _original: { name: '鈴木', age: -12, location: '大阪' },
  details: [
    {
      message: '"age" must be greater than or equal to 0',
      path: [Array],
      type: 'number.min',
      context: [Object]
    }
  ]
}

これも想定通りError [ValidationError]: "age" must be greater than or equal to 0というエラーが出ました。

サーバーサイドにおけるバリデーションチェック

では、htmlファイルで簡単にログインフォームを作成して、express内でバリデーションチェックを実装してみたいと思います。

まず、login.htmlファイルを作成します。

login.html
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>ログイン</title>
  <!-- axiosパッケージをインポートする -->
  <script src="https://unpkg.com/axios@1.6.7/dist/axios.min.js"></script>
</head>
<body>
    <div>
      <label>
        username: 
        <input type="text" class="username">
      </label>
    </div>
    <div>
      <label>
        password: 
        <input type="password" class="password">
      </label>
    </div>
    <button>ログイン</button>
    <p class="errorMessage"></p>

    <script>
      const uname = document.querySelector('.username')
      const pw = document.querySelector('.password')
      const button = document.querySelector('button')
      const errorMessage = document.querySelector('.errorMessage')

      button.addEventListener('click', async () => {
        await axios.post('http://localhost:3000/login', {
          username: uname.value,
          password: pw.value
        }).then(res => {
          errorMessage.style.color = 'blue'
          errorMessage.innerHTML = res.data
        }).catch(error => {
          errorMessage.style.color = 'red'
          errorMessage.innerHTML = error.response.data.message
        })
      })
    </script>
</body>
</html>

login.htmlは、usernamepasswordの値をサーバーに投げかけ、返ってきた結果を受け取って画面に表示するようになっています。

次にサーバーサイドのindex.jsファイルを作成します。

index.js
const express = require('express')
const Joi = require('joi')
const cors = require('cors')
const app = express()

const loginSchema = Joi.object({
  // username: 文字列、アルファベットor数字、3文字以上、省略不可
  username: Joi.string().alphanum().min(3).required(),
  // password: 文字列、6文字以上、省略不可
  password: Joi.string().min(6).required()
})

app.use(express.json())
app.use(cors())

app.post('/login', (req, res) => {
  // req.bodyがloginSchemaの定義に沿っていなければ、変数errorにエラーが入る
  const { error } = loginSchema.validate(req.body)
  if (error) {
    return res.status(400).json({ message: error.details[0].message })
  }
  res.send('ログイン成功!')
})

app.listen(3000, () => {
  console.log('Server is running on http://localhost:3000')
})

index.jsでは、loginSchemaを定義し、app.post('/login', ...)APIでvalidateメソッドを使ってreq.bodyの形式が定義した通りになっているかをチェックしている。errorが存在する場合はエラー内容を返し、存在しない場合は'ログイン成功!'を返す。

完成したものは下記のようになります。

Animation.gif

0
0
0

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?