ServiceNowのClient ScriptとBusiness Ruleは、どちらもJavaScriptで値を制御できます。しかし、Client Scriptは利用者のブラウザ上でフォーム操作に反応し、Business Ruleはサーバー上でDB操作に反応します。この実行場所の違いを無視すると、API更新だけ検証をすり抜ける、フォームが遅い、同じレコードを再更新して再帰する、といった問題が起きます。
この記事ではPDIで検証用Client Scriptレコードを作成し、設定がsys_script_clientへ保存され、新規Incidentフォームの返却HTMLへonChangeハンドラが組み込まれるところまで確認しました。Business Ruleは保存前のIncidentと保存後のDB値を比較し、Descriptionがbefore Business Ruleで補完される実動作を確認しています。
検証の透明性
- Client Script:設定保存とフォームへのハンドラ配信を確認。記事作成に使った自動ブラウザ経路ではServiceNowのインラインフォームランタイムが実行されなかったため、UI自動変更のスクリーンショットを「実行成功」として掲載していません。
- Business Rule:保存前後の同一IncidentでDescriptionのDB反映を確認。
- 検証用Client ScriptとBusiness Ruleは確認後にActiveオフ。
- Client Scriptの実行タイミング・制限はServiceNow公式ドキュメントと照合。
検証日:2026年7月19日。UI TypeやWorkspace対応はリリース・画面・サポートAPIにより異なります。
Client ScriptとBusiness Ruleの違い
| 比較軸 | Client Script | Business Rule |
|---|---|---|
| 実行場所 | 利用者のWebブラウザ | ServiceNowサーバー |
| 主な起点 | onLoad、onChange、onSubmit、onCellEdit | query、insert、update、delete。before、after、async、display |
| 主な用途 | フォームの操作性、入力支援、即時メッセージ | DB整合性、保存前補正、関連レコード処理 |
| API・Importにも効くか | 原則効かない。フォーム/検索画面中心 | 対象DB操作に一致すれば効く |
| セキュリティ用途 | 不可。表示制御だけで機密保護しない | 整合性には使えるが、アクセス保護はACL |
| 主な保存先 | sys_script_client | sys_script |
PDI検証1:onChange Client Scriptを設定する
検証用Client Script「Codex Demo - Client Script description」を作成しました。TableはIncident、UI TypeはAll、TypeはonChange、Field nameはShort descriptionです。Short descriptionが「Codex CS demo」で始まり、Descriptionが空の場合だけ、Descriptionへ検証文を設定する小さな処理です。
function onChange(control, oldValue, newValue, isLoading, isTemplate) {
if (isLoading || newValue === '') {
return;
}
if (newValue.indexOf('Codex CS demo') === 0 &&
g_form.getValue('description') === '') {
g_form.setValue(
'description',
'Client Scriptが保存前のフォームに設定しました。'
);
}
}
入力時に確認する項目
- Table:対象フォームのテーブルを選びます。
- UI Type:Core UI、Portal、Workspaceなど対象UIとAPI互換性を確認します。
- Type:値変更ならonChange、初期表示ならonLoad、送信検証ならonSubmitです。
- Field name:onChangeが監視するフィールドを指定します。
- isLoading / newValue:フォーム表示時の不要実行と空値処理を最初に除外します。
保存後、Client Scripts一覧で同名レコードが表示され、Active、Table、TypeなどがDBへ保存されたことを確認しました。さらに新規Incidentフォームのサーバー応答には、このレコードのsys_idとonChange_incident_short_descriptionハンドラが含まれていました。つまり「設定レコードがある」だけでなく、フォームへ配信対象として選ばれたところまで確認できました。
ただし、Client ScriptがDescriptionへ設定した値は、その瞬間にはブラウザのフォーム状態です。利用者がSubmitし、サーバー側の検証を通って初めてIncidentレコードへ保存されます。Client Scriptだけをデータ整合性の唯一の防御にすると、Import Set、REST API、サーバースクリプト、対応外UIからの更新が同じ制御を通らない可能性があります。
PDI検証2:before Business RuleでDB保存前に補正する
Business Rule側では、Incidentのinsert前に、Short descriptionが検証用接頭辞で始まり、Descriptionが空の場合だけ値を補完しました。Whenはbefore、Insertを有効、対象条件を検証文字列へ限定しています。
(function executeRule(current, previous) {
if (gs.nil(current.description)) {
current.description = 'Business Ruleが保存前に設定しました。';
}
})(current, previous);
before Business Ruleではcurrent.descriptionへ代入するだけで、通常はcurrent.update()を呼びません。before処理の変更は進行中のinsert/updateへ含まれるため、追加updateは再帰、二重実行、監査ノイズ、性能低下の原因になります。
保存前のIncident
新規Incidentに検証用Short descriptionを入力し、Descriptionは空のままにしました。この時点ではまだDBレコードとして保存されていません。
保存後の同一Incident
Submit後に同一Incidentを開くと、DescriptionへBusiness Ruleの文が保存されていました。画面上の見た目だけでなく、保存済みレコードのフィールド値として確認できたため、サーバー側のbefore処理がDB書き込みへ含まれたことが分かります。
どちらを使うべきか
| 要件 | 第一候補 | 補足 |
|---|---|---|
| 入力中に関連フィールドを表示・非表示にしたい | UI Policy / Client Script | 宣言的に書けるならUI Policyを優先 |
| フィールド変更直後に候補値を表示したい | onChange Client Script | サーバー参照は非同期GlideAjaxを検討 |
| フォーム送信前に簡単な入力不足を通知したい | onSubmit Client Script | 同じ整合性をサーバー側でも保証 |
| API・Import・Flowを含む全経路で保存値を補正したい | before Business Rule / Data Policy | 要件によりDictionaryやData Policyを優先 |
| 保存後に関連レコードを即時更新したい | after Business Rule | 同一レコードの再updateを避ける |
| 利用者を待たせず後続処理したい | async Business Rule / Flow | 順序保証と再試行要件を確認 |
| 機密フィールドを読ませたくない | ACL | Client Scriptで隠すだけでは保護にならない |
Client Scriptのベストプラクティス
1. まずUI Policyで表現できるか確認する
Mandatory、Visible、Read-onlyの単純制御はUI Policyの方が意図を読みやすく、保守しやすい場合があります。複雑な値操作や動的選択肢など、スクリプトが必要な部分だけClient Scriptへ置きます。
2. onChangeの先頭で不要実行を止める
isLoading、空値、対象外の値を早期returnし、フォームロードのたびに重い処理を実行しないようにします。Client ScriptにはConditionフィールドがないため、コード内のガードが重要です。
3. 同期サーバー参照を避ける
フォーム上のデータを優先し、サーバー参照が必要なら非同期GlideAjaxを検討します。g_form.getReference()やクライアント側GlideRecordで全フィールドを取得する設計は、公式ベストプラクティスでも性能上推奨されていません。
4. UIごとにテストする
Core UIで動いてもService PortalやWorkspaceで同じAPIが使えるとは限りません。UI TypeをAllにするだけで互換性が保証されるわけではないため、対象UIで実際にonLoad、onChange、onSubmitを通します。
5. Client Scriptをセキュリティに使わない
ブラウザ側制御は利用者体験を整える機能です。APIや別UIからのアクセスを防ぐものではありません。機密性はACL、必須・形式の整合性はDictionary、Data Policy、Business Ruleなどサーバー側でも保証します。
Business Ruleのベストプラクティス
1. 条件を狭くする
Table、Insert/Update、Filter Conditions、Advanced Conditionを使い、関係ないレコードで処理を走らせません。updateの場合はchanges()やchangesTo()を検討します。
2. 同一レコードの補正はbeforeを優先
保存するcurrentの値を変えるだけならbeforeで代入し、元のDB操作へ含めます。afterでcurrentを再updateしないようにします。
3. 再利用ロジックはScript Includeへ分ける
Business Ruleへ長い処理を複製すると修正漏れが起きます。Business Ruleには実行条件と呼び出しを残し、テスト可能な業務ロジックをScript Includeへ分離します。
4. asyncの順序と以前値に注意する
asyncは利用者の保存待ち時間を減らせますが、即時順序やprevious値に依存する処理には向きません。イベント、Flow、Scheduled処理を含め、再試行と重複防止を設計します。
検証用レコードの後始末
証拠取得後、Client ScriptはActive=falseへ変更し、Business Ruleも無効のままにしました。検証用自動処理をPDIへ残すと、後日の別テストへ影響し「なぜ値が変わったか」が分からなくなります。削除できない事情がある場合も、名前・Description・Active状態・対象条件を残し、無効化を確認します。
CSA理解確認問題
問題:フォーム、REST API、Import Setのどの経路からIncidentが作成されても、保存前にDescriptionの既定値を保証したい場合、最も適した第一候補はどれですか。
- onLoad Client Script
- onChange Client Script
- before Business Rule
- UI Policy
解答と解説
正解:C。Client ScriptとUI Policyはフォーム中心のクライアント処理です。DB操作の経路をまたいで保存前補正を保証する要件では、サーバー側のbefore Business Ruleが適します。ただし単純な既定値や必須制御ならDictionaryやData Policyも比較します。
まとめ
Client Scriptはブラウザで入力体験を改善し、Business RuleはサーバーでDB操作を制御します。PDIでは両者の設定保存先を分け、Business Ruleについては保存前後の同一IncidentでDB反映を確認しました。「画面で動いた」だけで完了せず、API・Import・別UI・権限・保存後レコードまで試すことが、保守しやすい実装につながります。
Business RuleとFlow Designerの違い / ACLとRoleの違い / CAD学習ガイド








