プログラミング入門(JavaScript) 関数に関数を渡してコードの重複をなくす例

エラーコードからエラーの文字を返す課題
今回は実務でありそうな課題をやってみます。
実装内容
ユーザー情報を返してくれるAPIがあります。
このAPIはエラーになった際に{code:’U001′}のようなオブジェクトを返します。
codeの値に応じた文字を返すような実装をして欲しいとのことです。
エラーコードは三種類あり、それぞれに対する文字列は以下です。
- U001 — ユーザーIDがありません
- U002 — ユーザーIDが誤っています
- U003 — 無効なユーザーIDです
- それ以外 — ユーザーの取得に失敗しました
注意点として、APIで予期せぬエラーになった際には、nullかundefinedが返ってくるとのことです。
例えば {code: 'U002’} の場合は、「ユーザーIDが誤っています」という文字列を返すようにします。
実装してみる
とりあえず関数で実装してみます。
const handleUserError = (error) => {
if(error === null || error === undefined) return '予期せぬエラー'
switch(error.code){
case 'U001':
return 'ユーザーIDがありません'
case 'U002':
return 'ユーザーIDが誤っています'
case 'U003':
return '無効なユーザーIDです'
default:
return 'ユーザーの取得に失敗しました'
}
}
これでも十分動作します。
追加の依頼
追加で、カスタマー情報を取得するAPIのエラーについても、同様のことをして欲しいとの依頼がありました。
- C001 — カスタマーIDがありません
- C002 — カスタマーIDが誤っています
- C003 — 無効なカスタマーIDです
- それ以外 — カスタマーの取得に失敗しました
APIで予期せぬエラーになった際には、nullかundefinedが返ってくるのは一緒とのことです。
以下のように実装しました。
const handleCustomerError = (error) => {
if(error === null || error === undefined) return '予期せぬエラー'
switch(error.code){
case 'C001':
return 'カスタマーIDがありません'
case 'C002':
return 'カスタマーIDが誤っています'
case 'C003':
return '無効なカスタマーIDです'
default:
return 'カスタマーの取得に失敗しました'
}
}
リファクタリングしてみる
二つの関数をみると、はじめのif文が共通しています。
今後、ユーザーやカスタマー以外にも、同じような関数を追加する必要がありそうです。その度に、同じif文をもった関数が増えていきます。
もし仕様が変わって、nullやundefinedの時は’予期せぬエラー’を返す、という動作が変わった場合、すべての関数に対して同じ修正をしなくてはいけません。
そこで、関数に関数を渡せるという強力な特性を使って重複をなくします。
const handleError = (error, handleFunc) => {
if(error === null || error === undefined) return '予期せぬエラー'
return handleFunc(error.code)
}
const userError = (code) => {
switch(code){
case 'U001':
return 'ユーザーIDがありません'
case 'U002':
return 'ユーザーIDが誤っています'
case 'U003':
return '無効なユーザーIDです'
default:
return 'ユーザーの取得に失敗しました'
}
}
const customerError = (code) => {
switch(code){
case 'C001':
return 'カスタマーIDがありません'
case 'C002':
return 'カスタマーIDが誤っています'
case 'C003':
return '無効なカスタマーIDです'
default:
return 'カスタマーの取得に失敗しました'
}
}
handleError({code: 'U002'},userError) //ユーザーIDが誤っています
handleError({code: 'C003'},customerError) //無効なカスタマーIDです
共通する処理はhandleErrorに持たせて、それぞれ振る舞いが異なるswitch文の部分は、関数(第二引数のhandleFunc)で渡せるようにしています。
userErrorとcustomerErrorは、switch文のみになることで、責務が明確になりシンプルになりました。
このように、関数に関数を渡すことで柔軟なコードを書くことができます。
補足
補足ですが、カリー化すると、handleErrorの第二引数にuserErrorやcustomerErrorを毎回渡さなくても済むようになります。
カリー化については、またの機会に書こうと思います。
const handleError = (handleFunc) => (error) => {
if(error === null || error === undefined) return '予期せぬエラー'
return handleFunc(error.code)
}
const userError = (code) => {
switch(code){
case 'U001':
return 'ユーザーIDがありません'
case 'U002':
return 'ユーザーIDが誤っています'
case 'U003':
return '無効なユーザーIDです'
default:
return 'ユーザーの取得に失敗しました'
}
}
const customerError = (code) => {
switch(code){
case 'C001':
return 'カスタマーIDがありません'
case 'C002':
return 'カスタマーIDが誤っています'
case 'C003':
return '無効なカスタマーIDです'
default:
return 'カスタマーの取得に失敗しました'
}
}
const handleUserError = handleError(userError)
const handleCustomerError = handleError(customerError)
handleUserError({code: 'U002'})
handleCustomerError({code: 'C003'})
ディスカッション
コメント一覧
まだ、コメントがありません