住所変換機のコードの見直しを続ける。
数回にわたって、郵便番号の入力の有無をチェックする関数(checkPostalCodeInput)と、郵便番号の入力が7桁の数字かをチェックする関数(validatePostalCode)の修正を完了した。
今回は、郵便番号入力で住所を自動的に取得する関数getAddressFromPostalCodeを見直していきたいと思う。この機能は多くの住所入力が必要なサイトに実装されている。
fetch APIはネット通信を行い、非同期処理の結果を管理する組み込み関数である
さて、ChatGPTが作ってくれたコードはこちらだ。
function getAddressFromPostalCode(postalCode) {
return new Promise((resolve, reject) => {
const url = `/get_address/${postalCode}`;
fetch(url)
.then(response => {
if (!response.ok) {
reject({ code: errorCodes.POSTAL_CODE_NOT_FOUND, field: 'postal_code' });
}
return response.json();
})
.then(json => {
if (json.prefecture && json.city && json.suburb) {
setFieldsDisabled(false);
resolve({
prefectureName: json.prefecture,
cityName: json.city,
choikiName: json.suburb,
postalCode: postalCode
});
} else {
reject({ code: errorCodes.POSTAL_CODE_NOT_FOUND, field: 'postal_code' });
}
})
});
}
この関数は、フォームに郵便番号が入力されたら、APIを通して住所を取りに行くが、住所情報が返ってくるのを待たないで、次のフォーム入力(例えば番地の入力)を受け付けるので、非同期処理にあたる。そのため、Promiseが使われている。
この関数はよく機能していて、内容も私の浅い理解では問題がないように見受けられるが、文法上よくわからないところがある。それが7行目のfetchだ。
いや感覚と文脈ではURLの情報を読み取る機能だとイメージできるのだが、知識としてちゃんと知りたい。
整理すると、fetchは次のように定義できるようだ。
- fetchはJavaScriptの組み込み関数である。
- ネットワークリクエストを行うための、PromiseベースのAPIである。
- サーバーと通信し、データを送受信できる。
- 非同期処理の結果を管理できる。
このfetchの基本構文は記事の最初のコードと大体一致しているが、catchブロックがあるところに違いがある。これは後で聞こうと思う。以下fetchの動作の詳細だ。
responseってなに?と調べたかったが、この回答でサーバーからのHTTPリクエストの結果が格納されたオブジェクトであることがわかった。
Catchブロックを追加する
ChatGPTが紹介するfetchの動作の詳細も、だいたい先頭のコードと一致している。だがさっきも言ったように、先頭のコードにcatchブロックがない。そこで、catchを追加すべきか聞いてみた。
追加したほうがいいそうだ。じゃ何で最初に書いてくれなかったんだよって話だけど、AIに文句を言ってもしょうがない。catchを追加してもらうぞ!
上の修正ポイントに書かれているように、この修正で、catchの追加に伴い、もともとthenでそれぞれ行われていたエラー処理(reject)がcatchブロックにエラースローされ、まとめてエラー処理される仕組みになった。
そして上記の3番目のポイントのコンソール出力は要らないので、その行を削除し、コメントとエラーメッセージの日本語を少し修正し、最後には、コードを次のように仕上げた。
// 郵便番号から住所を取得
/**
* 郵便番号からAPIを通して住所を取得
*
* @param {string} postalCode - チェックする郵便番号
* @return {boolean} 7桁の数字ならtrue、でなければfalseを返す
*/
function getAddressFromPostalCode(postalCode) {
return new Promise((resolve, reject) => {
const url = `/get_address/${postalCode}`;
// fetch APIを使ってHTTPリクエストを送る
fetch(url)
// HTTPのレスポンスがとして、responseオブジェクトが返される
.then(response => {
// responseのokプロパティがfalseなら(リクエストが失敗したなら)
if (!response.ok) {
/// HTTPリクエストが失敗した場合はエラーを投げる
throw new Error ('HTTPのレスポンスがokではない');
}
// リクエスト成功の場合、reponseをjsonとしてパース
return response.json();
})
.then(json => {
// json形式のresponseに必要な部分が含まれているかをチェック
if (json.prefecture && json.city && json.suburb) {
// 郵便番号以外のフィールドを入力可能に
setFieldsDisabled(false);
// 非同期処理が成功した場合に必要なデータを引数としてresovle関数に渡す
resolve({
prefectureName: json.prefecture,
cityName: json.city,
choikiName: json.suburb,
postalCode: postalCode
});
} else {
// 受け取ったデータに、都道府県、市区町村、町域のうち、どれかがない場合にエラーを投げる
throw new Error ('不完全な住所データを受信した')
}
})
.catch(error => {
// エラーが発生した場合、rejectを通じてエラー情報を返す
reject({ code: errorCodes.POSTAL_CODE_NOT_FOUND, field: 'postal_code' });
})
});
}
JSDocコメント修正
でもちょっと待って!関数の説明コメントがちょっとおかしい。
具体的に言うと、@returnのところがこの関数の説明ではなく、validatePostalCode関数のものになっている。コピペしたものを放置したからだろう。
@return {boolean} 7桁の数字ならtrue、でなければfalseを返す
これで関数getAddressFromPostalCodeの修正が終わる。