自己認為學會一項新技能之後最興奮的就是怎麼運用到專案了,這篇會用每一個網站都需要處理的"串接 API "為例。從發 request 去要 API 資料一直到拿完資料並整型成 UI 想要得樣子,這中間有可能發生的錯誤實在太多了,所以導入 Either Monad 我覺得非常適合。
假如今天 API 回傳資料如以下
// response
{
data: [
{
email: 'foo@example.com',
'user-name': '34Cindy',
phone: '#465-876?'
},
{
email: 'foo!example?dd',
'user-name': '3-jsindy',
phone: '465-876-998'
},
{ email: 'foo@example',
'user-name': 'Hindy',
phone: '46587676'
}
]
}
我們的目標是要由前端 transform 成以下,最後再 render 到 DOM 上面
{
data: [
{
email: 'foo@example.com',
userName: 'CINDY',
phone: '465876'
},
{
email: 'foo@example',
userName: 'JSINDY',
phone: '465876998'
},
{ email: 'foo@example',
userName: 'HINDY',
phone: '46587676'
}
]
}
可能會用 map
然後
/*
Part A
*/
// ... 代表簡略
response.map(list => {
// list key 變 camelCase
...
// 一個一個 regex
let newEmail = list.email.match(regex) ...
let newName = list.userName.match(regex) ...
let newPhone = list.phone.match(regex) ...
return `${newName} / ${newEmail} / ${newPhone}`
})
然後另外要考慮 Edge Case
(↑ 有考慮 Edge Case,爆錯但可以引導使用者去別的地方)
/*
Part B
*/
fetch(url).then((response) => {
if (response.ok) {
return response.json();
} else {
// 處理錯誤 1
} })
.then((res) => {
if(list.length > 0){
response.map(list => {
// Part A
// Part A 也要處理錯誤
})
} else {
// 空值要做的事
}
.catch((error) => {
// 處理錯誤 2
});
我相信大家跟我一樣很熟悉以上寫法,這一包 Function 只適用當下 Page / Component,程式裡面也參雜了許多判斷式去判斷各種不同情況 (是不是空值、API 有沒有錯、API 回傳值是不是想要的格式等等)
讓我們先想一下需要步驟
user_name
統一變 camelCase userName
以上每個步驟都有可能有兩種結果
若從頭到尾都很順利,那就是一路運算下去
若中間突然有一 Failed,例如 3. validate data,就會跳過後面步驟直接顯示客製化錯誤訊息
若一開始就 Failed,同理可證,會略過接下來所有步驟直接顯示客製化錯誤訊息
下面會是程式碼大概的樣子,裡面有很多 utilities 但這些都是可以不斷 reuse 的,例如 getProp
、checkNoDataState
、handleError
... 等,程式碼也相當好閱讀與理解,這就是 FP 吸引人的地方吧!
const validateData = data =>
pipe(
isEmail('email'),
isPhoneNumber('phone'),
isName('userName'),
)(data[0]).map(() => data);
/**
* Validates & Transforms Data
*
* @param {ResponseState} response
* @return {ResponseState}
*/
function transform (response) {
return Box(response)
.chain(getProp('data'))
.chain(checkNoDataState(x => x.length === 0))
.chain(validateData)
.map(transformData)
.then(
(transforme) => ({
...response,
data: transforme
}),
handleError(response)
);
}
這邊有 hardcore-functional-js 課程提供串接 weather API 資料原始碼可以參考 ~~
如有錯誤或需要改進的地方,拜託跟我說。
我會以最快速度修改,感謝您
歡迎追蹤我的部落格,除了技術文也會分享一些在矽谷工作的甘苦。