🕵️‍♀️

Webエンジニア初心者を抜けるための3つのバリデーション

に公開
2024/08/15

ラブグラフのエンジニア兼CTO、横江 (@yokoe24) です。
この間インターンのかたに説明する機会があったので、こちらのブログでも。

3つのバリデーション

サーバーサイドアプリケーションの制作にあたっては
『3つのバリデーション』が必要になります。
バリデーション とは、入力された値をチェックする仕組みのことです。

データベースに変な値が保存されてアプリケーションが変な動きをしないために、
バリデーションはとても大事なものです。

そしてバリデーションは大きく3つ、

    1. フロントエンド のバリデーション
    1. サーバーサイド のバリデーション
    1. データベース のバリデーション

に分けられます。順番に見ていきましょう!

1. フロントエンドのバリデーション

フロントエンドのバリデーションは、
スマホアプリだったらスマホアプリ側の実装となりますが、
今回はWebアプリケーションを想定して、「HTMLバリデーション」と「JavaScriptバリデーション」について話します。

HTMLバリデーション

HTMLバリデーションは、例えば <input> タグがわかりやすいです。
inputタグの属性はいろいろありますが、その中でも

  • required: required="required" のとき、なんらかの入力を必須とし、入力欄が空のままだといけなくする
  • maxlength: 入力できる文字数の長さを制限する( <input type="text"> などで有効)
  • max, min: 入力できる値の最大値・最小値を指定する( <input type="number"> などで有効)

などは使う機会が多いと思います。

例えば required を設定すると、なにも記入せず送信ボタンを押すと、
以下のように表示が出て次に進むことができません。

JavaScriptバリデーション

スクショからだとわかりづらいのですが、
例えば以下は Vue.js で、Eメールの入力がない限り、
送信ボタンが disabled 状態になるようにしたものです。


https://jsfiddle.net/nekonenene/x7wjntpz/53

フロントエンドバリデーションの問題点

これらのフロントエンドバリデーションは、
ユーザー補助の観点ではいいのですが、Webアプリケーションを安全に運用するためには不完全です。

Chrome などウェブブラウザ側のデベロッパーコンソールで
HTML を書き換えて、 required や disabled などの条件を消してしまうことが簡単にでき、
フロントエンドバリデーションをなくした状態で送信できてしまいます。


ここを削除ボタンで消せば、


なかったことに!!!

JavaScript 側で入力内容をチェックして、
JavaScript 側で API リクエストを送るなどは、これよりは複雑でマシですが、
いちおう、JavaScript 側のコードを読めばバリデーションを無視したデータをサーバーに送りつけることが可能です。

2. サーバーサイドのバリデーション

フロントエンドバリデーションが突破されてしまったときに大事なのが、
サーバー側のバリデーションです!
ここがとっても大事です!

例えば Rails には、以下の Rails ガイドのようにモデルに様々なバリデーションを設定できます。

https://railsguides.jp/active_record_validations.html

class Message < ApplicationRecord
  validates :body, presence: true, length: { maximum: 200 }
end

のように書くことで、 Message の body の値として
空文字 " や、200文字より多いテキストを入れて保存しようとしたときにエラーを吐いてくれます。

コントローラー側では以下のように書いて、
body に問題があることをユーザー側に表示させるなどをおこなうことでしょう。

def create
  @message = Message.new(message_params)

  if @message.save
    redirect_to messages_path, notice: "メッセージを作成しました"
  else
    redirect_to new_message_path(@message), alert: @message.errors.full_messages.join(", ")
  end
end

private

def message_params
  params.require(:message).permit(:body)
end

また、モデル側に条件があるのではなく、
コントローラー側で保存しようとする内容や、保存しようとしているユーザーの権限などをチェックし、
問題があればリダイレクトするなども、サーバー側のバリデーションと言えるでしょう。

このようなサーバーバリデーションによって、
望ましくないデータが保存されることを防ぐことはとても大切です!

エンジニア初心者〜中級者にかけて、 1. のフロントエンドバリデーションの実装で満足してしまって
サーバーサイドのバリデーションをかけていないということはよくあるので、
フロントエンドバリデーションをかけた際には 「これに対するサーバーサイドバリデーションは書けていたっけな?」 と、セットのように考えることをオススメします😉

3. データベースのバリデーション

最後の砦、データベースのバリデーションです。
これは NOT NULL 制約や UNIQUE (ユニーク)制約などがよく使われると思います。

例えば Rails で以下のように create_table した場合を考えます。

create_table :products do |t|
  t.string :uuid, null: false
  t.string :name, null: false, default: ""
  t.integer :price, null: false
  t.text :description

  t.timestamps

  t.index :uuid, unique: true
  t.index :price
end

こうすると、 price カラムを未定義、つまり NULL の状態でデータを入れようとすると
データベースはエラーを吐き、 INSERT や UPDATE がおこなわれることを防いでくれます。

また、 uuid カラムにはユニークインデックスが貼られているので、
すでに登録されているデータと同じ文字列の uuid を設定しようとした際もエラーを吐いてくれます。

このように、想定されていないデータをデータベース側で弾くことが可能です。

ただし、 できるだけサーバーバリデーションで防いでおいて、データベースバリデーションが実行されてDBからサーバーにエラーが返されるというのは防ぎたいものです。
けっこうDBエラーの例外処理って抜けていて 500 エラーになりがちですしね。

データベースバリデーションは、やむをえぬ事情でサーバーを介さずに
DBに直接 INSERT や UPDATE のクエリを流さないといけないときに
変なデータが入ることを防ぐためにも役立ってくれることでしょう。
(そういうこともないといいですが……)

おわりに

以上、Webアプリケーション制作に必要な3つのバリデーションについてまとめました。

特に サーバーサイドのバリデーションが超大事! ってことが伝わりましたら幸いです!

ラブグラフのエンジニアブログ

Discussion