今回は、J-Quants APIからデータを取得するときに、ブラウザ・Next.js・FastAPI・J-Quantsの間で、どのようにデータが流れているのかを整理します。
コードを書いていると、
「fetchって結局何をしているんだろう?」
「localhost:3000と127.0.0.1:8000は何が違うの?」
「FastAPIからJ-Quantsにはどうやってアクセスしているの?」
「CORSはどこで何をチェックしているの?」
と、個々のコードは分かっても、全体のつながりが分からなくなることがあります。
そこで今回は、実際に作成している株式分析アプリのコードを使いながら、通信の流れを整理してみました。
動画はこちら
今回の内容はYouTubeでも説明しています。

全体の流れ
今回作っている仕組みでは、大まかに次のようにデータが流れています。
ブラウザ(Next.js)
↓ fetchでHTTPリクエスト
FastAPI
↓ HTTPリクエスト
J-Quants API
↓ JSONデータを返す
FastAPI
↓ 必要なデータを加工して返す
ブラウザ(Next.js)
この一連の流れによって、J-Quantsから取得した会社情報をWeb画面に表示しています。
今回は、この流れをもう少し細かく見ていきます。
localhostとポート番号
まず最初に理解しておきたいのが、localhostとポート番号です。
開発環境では、Next.jsを
http://localhost:3000
で動かしています。
一方、FastAPIは
http://127.0.0.1:8000
で動かしています。
localhostと127.0.0.1は、どちらも基本的に自分自身のPCを指しています。
つまりNext.jsもFastAPIも、同じパソコンの中で動いています。
では何が違うのかというと、ポート番号です。
Next.jsは3000番、FastAPIは8000番を使っています。
同じPCの中でも、
localhost:3000
と
127.0.0.1:8000
では別の場所として扱われます。
イメージとしては、同じ建物の中にある別々の部屋のようなものです。
今回の場合、
3000 → Next.js
8000 → FastAPI
というように役割を分けています。
Next.jsからFastAPIへアクセスする
Next.js側では、fetch()を使ってFastAPIへアクセスしています。
イメージとしては次のような処理です。
fetch("http://127.0.0.1:8000/jquants-companies")
これは、
「127.0.0.1の8000番で動いているFastAPIの /jquants-companies にデータをください」
というHTTPリクエストを送っています。
つまり、
Next.js
↓ fetch
FastAPI
という通信がここで発生しています。
fetchとは?
fetch()は、JavaScriptからHTTPリクエストを送るために利用できる仕組みです。
指定したURLに対して、
データをください
というリクエストを送ることができます。
今回の場合は、ブラウザからFastAPIに対してリクエストを送っています。
ただし、リクエストを送った瞬間にデータが返ってくるとは限りません。
通信には時間がかかるからです。
そこで登場するのがPromiseです。
Promiseとは?
fetch()を実行すると、Promiseが返されます。
Promiseは、非同期処理の結果を扱うための仕組みです。
通信中には、
まだ結果が返ってきていない
という時間があります。
そのためPromiseには、処理の状態があります。
代表的なのが次の3つです。
pending
まだ処理が終わっていない状態です。
データをください
↓
現在通信中……
という状態です。
fulfilled
処理が正常に完了した状態です。
データをください
↓
データが返ってきた
という状態です。
rejected
何らかの理由で処理に失敗した状態です。
例えば、接続先にアクセスできなかった場合などです。
thenとcatch
Promiseの結果に応じて処理を続けるために使われるのが、then()やcatch()です。
例えば、
fetch(...)
.then(...)
.then(...)
.catch(...)
という処理があったとします。
まずfetch()でHTTPリクエストを送ります。
正常にレスポンスが返ってきたら、最初のthen()が実行されます。
ここでは、受け取ったレスポンスをJSONとして扱えるように変換します。
response.json()
さらにJSONへの変換が成功すると、次のthen()が実行されます。
ここで実際のデータを利用した処理を行います。
一方、途中でエラーが発生した場合はcatch()へ進みます。
つまり大まかには、
fetch
↓
成功
↓
then
↓
成功
↓
then
となり、
どこかで失敗すると、
catch
へ進みます。
こうして、通信の成功・失敗を扱えるようになっています。
FastAPI側では何をしているのか
次はバックエンド側です。
Next.jsから、
/jquants-companies
へアクセスすると、FastAPI側の対応する処理が実行されます。
つまり、
Next.js
↓
FastAPI /jquants-companies
となります。
FastAPIはリクエストを受け取ると、今度はJ-Quants APIへアクセスします。
ここではPythonのHTTPリクエストを使って、
FastAPI
↓
J-Quants API
という通信を行います。
J-QuantsからJSONデータを受け取る
J-Quants APIへリクエストを送ると、レスポンスとしてデータが返ってきます。
このレスポンスはJSON形式になっています。
そのためFastAPI側でJSONをPythonから扱える形に変換します。
そして、取得した会社情報の中から必要なデータだけを取り出します。
今回のコードでは、J-Quantsから取得した大量の会社データの中から、ProdCatが011のものを抽出しています。
011は普通株式を表しているため、ETFやREITなどを除外し、対象となる会社データを取り出しています。
イメージとしては、
J-Quants
↓
大量の会社情報
↓
ProdCat = 011 の会社を抽出
↓
必要な会社データだけ残す
という処理です。
そしてFastAPIが、その結果をNext.js側へ返します。
最終的なデータの流れ
ここまでをまとめると、次のようになります。
① Next.js
↓
fetch()
② FastAPI
↓
HTTPリクエスト
③ J-Quants API
↓
JSONレスポンス
④ FastAPI
↓
JSONを処理
↓
必要な会社だけ抽出
⑤ ブラウザ
↓
⑥ Next.jsでデータを利用・表示
こうして、J-Quantsのデータが最終的にブラウザ上に表示されます。
CORSとは?
ここでもう1つ出てくるのがCORSです。
今回、
Next.js
localhost:3000
と
FastAPI
127.0.0.1:8000
は、別のオリジンとして扱われます。
そのため、ブラウザは自由にデータを受け渡しさせるわけではありません。
FastAPI側ではCORSの設定を行い、
http://localhost:3000
からのアクセスを許可しています。
FastAPIからレスポンスが返ってくる際には、アクセスを許可するオリジンに関する情報も含まれます。
そしてブラウザがその情報を確認します。
問題がなければ、ブラウザからNext.js側のJavaScriptでレスポンスを利用できます。
ここで重要なのは、CORSを実際にチェックしているのはブラウザという点です。
FastAPIは、
このオリジンからのアクセスを許可します
という情報をレスポンスに付けます。
それを見て、ブラウザがJavaScriptからレスポンスを利用させてもよいか判断します。
今回のまとめ
今回の処理を理解するうえで重要だったのは、次の流れです。
Next.js
↓
fetch
↓
FastAPI
↓
J-Quants API
↓
FastAPI
↓
ブラウザ
↓
Next.js
Next.jsとFastAPIは同じPC上で動いていますが、それぞれ3000番・8000番という異なるポートを使っています。
Next.jsではfetch()を使ってFastAPIへHTTPリクエストを送ります。
fetch()の結果はPromiseとして扱われ、通信中・成功・失敗といった状態を持ちます。
処理が成功した場合はthen()を使ってレスポンスをJSONへ変換し、そのデータを利用します。
FastAPIはNext.jsからリクエストを受け取ると、J-Quants APIへアクセスします。
J-Quantsから取得したJSONデータをPythonで処理し、必要な会社情報だけを抽出してNext.js側へ返します。
さらに、ブラウザとFastAPIの間ではCORSの仕組みがあり、許可されたオリジンからの通信なのかをブラウザが確認しています。
コードだけを1行ずつ見ていると少し分かりづらいですが、
「今、誰が誰にデータを要求しているのか?」
を意識すると、かなり理解しやすくなりました。
今回の内容はYouTubeでも、実際のコードや画面を見ながら説明しています。

私自身もまだ学習中なので、実際にアプリを作りながら理解したことを今後もまとめていこうと思います。

コメント