diff --git a/7-bank-project/3-data/translations/README.ja.md b/7-bank-project/3-data/translations/README.ja.md new file mode 100644 index 00000000..998ab7f4 --- /dev/null +++ b/7-bank-project/3-data/translations/README.ja.md @@ -0,0 +1,332 @@ +# バンキングアプリを作ろう その 3: データの取得と利用方法 + +## レッスン前の小テスト + +[レッスン前の小テスト](https://nice-beach-0fe9e9d0f.azurestaticapps.net/quiz/45) + +### イントロダクション + +すべての Web アプリケーションの中核には、*データ*があります。データには様々な形がありますが、その主な目的は常にユーザーに情報を表示することです。Web アプリケーションがますますインタラクティブで複雑になってきているため、ユーザーがどのように情報にアクセスして対話するかは、現在では Web 開発の重要な部分となっています。 + +このレッスンでは、サーバーから非同期にデータを取得し、このデータを使用して HTML をリロードせずに Web ページに情報を表示する方法を見ていきます。 + +### 前提条件 + +このレッスンでは、Web アプリの[ログインと登録フォーム](../../2-forms/translations/README.ja.md)の部分をビルドしておく必要があります。また、アカウントデータを取得するためには、ローカルに [Node.js](https://nodejs.org) と [サーバー API を実行する](../../api/translations/README.ja.md)をインストールする必要があります。 + +ターミナルで以下のコマンドを実行することで、サーバーが正常に動作していることを確認できます。 + +```sh +curl http://localhost:5000/api +# -> 結果として "Bank API v1.0.0" を返す必要があります。 +``` + +--- + +## AJAX とデータ取得 + +従来の Web サイトでは、ユーザーがリンクをクリックしたり、フォームを使用してデータを送信したりした際に、HTML ページ全体をリロードすることで表示されるコンテンツを更新しています。新しいデータの読み込みが必要になるたびに、Web サーバはブラウザで処理する必要のある新しい HTML ページを返し、現在のユーザのアクションを中断し、リロード中のインタラクションを制限します。このワークフローは、*マルチページアプリケーション* または *MPA* とも呼ばれます。 + +![複数ページのアプリケーションでワークフローを更新する](../images/mpa.png) + +Web アプリケーションがより複雑でインタラクティブになり始めた頃、[AJAX (Asynchronous JavaScript and XML)](https://en.wikipedia.org/wiki/Ajax_(programming))と呼ばれる新しい技術が登場しました。この技術は、Web アプリケーションが HTML ページをリロードすることなく、JavaScript を使ってサーバーから非同期にデータを送受信することを可能にし、結果として、より高速な更新とよりスムーズなユーザーのインタラクションを実現します。サーバーから新しいデータを受信すると、[DOM](https://developer.mozilla.org/ja/docs/Web/API/Document_Object_Model) API を使用して現在の HTML ページを JavaScript で更新することもできます。時間の経過とともに、このアプローチは現在では [*シングルページアプリケーション* または *SPA*](https://en.wikipedia.org/wiki/Single-page_application) と呼ばれているものへと発展してきました。 + +![シングルページアプリケーションでワークフローを更新](../images/spa.png) + +AJAX が最初に導入されたとき、データを非同期で取得できる唯一の API は [`XMLHttpRequest`](https://developer.mozilla.org/ja/docs/Web/API/XMLHttpRequest/Using_XMLHttpRequest) でした。しかし、現在のブラウザはより便利で強力な [`Fetch` API](https://developer.mozilla.org/ja/docs/Web/API/Fetch_API) を実装しており、Promise を使用し、JSON データを操作するのに適しています。 + +> 最新のブラウザはすべて `Fetch API` をサポートしていますが、もしあなたの Web アプリケーションをレガシーブラウザや古いブラウザで動作させたいのであれば、最初に [caniuse.com の互換性テーブル](https://caniuse.com/fetch) をチェックするのが良いでしょう。 + +### タスク + +[前回のレッスン](../../2-forms/translations/README.ja.md)では、アカウントを作成するための登録フォームを暗示しました。ここでは、既存のアカウントを使ってログインし、そのデータを取得するコードを追加します。`app.js` ファイルを開き、新しい `login` 関数を追加します。 + +```js +async function login() { + const loginForm = document.getElementById('loginForm') + const user = loginForm.user.value; +} +``` + +ここではまずフォーム要素を `getElementById()` で取得し、入力からユーザ名を `loginForm.user.value` で取得します。すべてのフォームコントロールは、フォームのプロパティとしてその名前 (HTML では `name` 属性を使って設定されています) によってアクセスすることができます。 + +登録の際に行ったことと同様の方法で、フォームコントロールにアクセスすることができます。サーバーリクエストを実行するために別の関数を作成しますが、今回はアカウントデータを取得します。 + +```js +async function getAccount(user) { + try { + const response = await fetch('//localhost:5000/api/accounts/' + encodeURIComponent(user)); + return await response.json(); + } catch (error) { + return { error: error.message || 'Unknown error' }; + } +} +``` + +ここでは `fetch` API を使ってサーバから非同期にデータを要求しますが、今回はデータを問い合わせるだけなので、呼び出す URL 以外の余分なパラメータは必要ありません。デフォルトでは、`fetch` は [`GET`](https://developer.mozilla.org/ja/docs/Web/HTTP/Methods/GET) HTTP リクエストを作成します。 + +✅ `encodeURIComponent()` は URL の特殊文字をエスケープする関数です。この関数を呼び出さずに URL の `user` の値を直接使うと、どのような問題が発生する可能性があるのでしょうか? + +それでは、`login` 関数を `getAccount` を使うように更新してみましょう。 + +```js +async function login() { + const loginForm = document.getElementById('loginForm') + const user = loginForm.user.value; + const data = await getAccount(user); + + if (data.error) { + return console.log('loginError', data.error); + } + + account = data; + navigate('/dashboard'); +} +``` + +まず、`getAccount` は非同期関数なので、これを `await` キーワードにマッチさせてサーバの結果を待つ必要があります。他のサーバからのリクエストと同様に、エラーが発生した場合にも対処しなければなりません。今のところ、エラーを表示するためのログメッセージを追加して、それをレイヤーに戻すだけです。 + +その後、データをどこかに保存しておく必要があるので、後でダッシュボードの情報を表示するためにデータを使用することができます。変数 `account` はまだ存在しないので、ファイルの先頭にグローバル変数を作成します。 + +```js +let account = null; +``` + +ユーザデータが変数に保存された後、既に持っている `navigate()` 関数を使って *ログイン* ページから *ダッシュボード* に移動することができます。 + +最後に、HTML を修正してログインフォームが送信されたときに `login` 関数を呼び出す必要があります。 + +```html +