はじめに
皆さんこんにちは。サイボウズ株式会社テクニカルトレーナーのTeruです。
今回はkintoneカスタマイズにおけるtry/catchの使い方を考えていきましょう!
try/catchの基本
そもそも、try/catchは例外が発生した場合に例外を処理するために使用します。
try {
実行する処理
} catch(e) {
try文で例外が発生した場合に実行される処理
}
例外とは、kintoneカスタマイズにおいては多くの場合 REST API の実行に失敗した場合のことです。
サンプル
例えば、アプリ番号:1 レコード番号:1
のレコードを取得する場合は下記のようにtry/catchを使用します。
try {
// レコード取得処理
await kintone.api('/k/v1/record', 'GET', { app: 1, id: 1 });
} catch (e) {
// レコード取得に失敗した場合の処理
console.error(e);
}
この取得処理でエラーが発生するのは、次のようなケースです。
- アプリが存在しない
- レコードが存在しない
- ネットワークエラー
仮にアプリが存在しなければ、console.error(e)
はこのようなエラーを表示します。
{code: 'GAIA_AP01', id: '8BwNVgSl5Z0XNrXaZbZI', message: '指定したアプリ(id: 1)が見つかりません。削除されている可能性があります。'}
ちなみにcatch(e)
のe
部分は自由に命名できますし、catch
内で使用しなければ省略することもできます。
省略する場合のサンプル
try {
// レコード取得処理
await kintone.api('/k/v1/record', 'GET', { app: 1, id: 1 });
} catch {
// レコード取得に失敗した場合の処理
console.error('取得に失敗しました');
}
複数の処理の扱い方
次に、複数の REST API を実行する場合のtry/catchについて扱っていきます。
例えば次のようなケースです。
-
アプリ番号:1 レコード番号:1
のレコードを取得する - 取得したレコードの値を用いて、
アプリ番号:2
にレコードを登録する
try/catchでひとまとめにするパターン
try {
// レコード取得処理
const resp = await kintone.api('/k/v1/record', 'GET', { app: 1, id: 1 });
// レコード登録処理
const params = {
app: 2,
record: {
氏名: {
value: resp.record.氏名.value,
},
},
};
await kintone.api('/k/v1/record', 'POST', params);
} catch (e) {
// 失敗した場合の処理
console.error(e);
}
この場合は、取得処理・登録処理のどちらかにエラーが発生した瞬間にcatch
へ飛びます。
処理が正常に終了しなかったことをユーザーに対してアラートを表示したり、コンソールにエラーを表示することができます。
しかし、このコードではどちらでエラーが発生したのかはcatch
内で判別ができません。
「取得に失敗しました」や「登録に失敗しました」といったエラー文の使い分けができないことになります。
では、それぞれにtry/catchを設定すれば良いのでは?と考える人もいるかもしれません。
try/catchを個別に設定するパターン(動作しません)
try {
// レコード取得処理
const resp = await kintone.api('/k/v1/record', 'GET', { app: 1, id: 1 });
} catch (e) {
// レコード取得に失敗した場合の処理
console.error(e);
}
try {
// レコード登録処理
const params = {
app: 2,
record: {
氏名: {
value: resp.record.氏名.value,
},
},
};
await kintone.api('/k/v1/record', 'POST', params);
} catch (e) {
// レコード登録に失敗した場合の処理
console.error(e);
}
今回のコードは動きません。
try
は{}
でスコープ(=変数がアクセスできる範囲)を作り出しています。
スコープ内で宣言された変数は外からアクセスすることができません。
よって、登録処理側でresp
にアクセスすることができないわけですね。
まあ一応解決策としてresp
を外でlet
を使って先に宣言してしまう方法もあるのですが、エラー処理のためにエラーが発生する要因を作ることになりかねないので非推奨です。
ではどのようにすればいいでしょうか。
await/catchを使うパターン
// レコード取得処理
const resp = await kintone.api('/k/v1/record', 'GET', { app: 1, id: 1 }).catch((e) => console.error('レコード取得失敗',e));
// レコード登録処理
const params = {
app: 2,
record: {
氏名: {
value: resp.record.氏名.value,
},
},
};
await kintone.api('/k/v1/record', 'POST', params).catch((e) => console.error('レコード登録失敗', e));
Promiseチェーンを活用してエラー処理を行うこともできるわけです。
try/catchでひとまとめにするパターンが楽でいいですけどね。
例外処理を発生させたいとき
kintoneカスタマイズではcatch
に飛ぶだろう・・・と想定していることがcatch
に飛ばないことがあります。
それは次のようなケースです。
-
アプリ番号:1
の最新の顧客番号を持つレコードを取得する - 取得した顧客番号に+1した値を顧客番号にセットして
アプリ番号:1
にレコードを登録する
この処理を行う時、もしレコードが一つもなかったらcatch
に飛ぶだろう・・・と思いませんか?
いいえ、飛びません。
レコードが一つもないのは、絞り込みで0件表示の時と同じ状態なのでエラーではないのです。
取得処理自体は成功している扱いになります。
こういう場合に使うのがthrow
です。例外を強制的に発生させることができます。
try {
// レコード取得処理
const resp = await kintone.api('/k/v1/record', 'GET', {
app: 283,
query: 'order by 顧客番号 desc limit 1',
});
// レコードが0件の場合は例外を発生させる
if (resp.records.length === 0) throw new Error('レコードが存在しません');
// レコード登録処理
const params = {
app: 285,
record: {
顧客番号: {
value: resp.records[0].顧客番号.value + 1,
},
},
};
await kintone.api('/k/v1/record', 'POST', params);
} catch (e) {
console.error(e);
}
このようにthrow
することでcatch
に強制的に飛ばすことができます。
まとめ
- REST API と try/catchはセットで使いましょう
- 個別にエラー処理をしたい場合は await/catchを使いましょう
- 例外を発生させたいときは throw を使いましょう