Expressの続きです。前回はMySQLとMongoDBに接続してみました。今回は「body-parser」を使って以前触れたFetch API(およびForm)のリクエストを受け取りレスポンスを返す動きを作ってみたく思います。それではいきましょう!
【目次】
- 前回のおさらい
- Node環境のWebサーバと静的なファイルを準備
- body-parserとは
- body-parserインストール
- Form送信の設定
- Fetch APIの通信設定
- 動作確認
- コード全体
- 最後に
※参考:前回記事
【Epxress】データベース接続の比較(MySQLとMongoDB) - クモのようにコツコツと
※参考:Node.js / Expressを習得するためにやったことまとめ
qiita.com
前回のおさらい
前回はExpressを使ってデータベースのMySQL、MongoDBに接続した。引き続き、接続したデータベースの内容をブラウザに返すAPIを作っていきたい。
※参考:【Epxress】データベース接続の比較(MySQLとMongoDB) - クモのようにコツコツと
以前、ExpressでURLへのリクエストに対して静的なHTMLファイル一式を表示させた。これはAPIというよりはApacheなどと同じWebサーバに相当する。
※参考:【Express】静的HTMLファイルの表示(res.sendFile()、express.static()) - クモのようにコツコツと
APIの場合は、FormやFetch APIなどによって送られてきたデータを受け取って、データベースなどに反映し、結果のJSONデータをレスポンスとして返したい。所謂「REST API」というやつ。
※参考:REST APIとは何かを調べまくったらようやくイメージができてきたのでまとめた - クモのようにコツコツと
そのためにはまず、ブラウザからのFormやFetch APIなどのデータを受け取る仕組みが必要。
Node環境のWebサーバと静的なファイルを準備
手順
まず最初にNode.js環境で構築したWebサーバにFetch APIのサンプを取り込む。サンプルは以前作ったこちら。
上のフォームがfornタグからの送信。下のフォームがFetch APIからの送信。
※参考:【JS】Fetch APIでPOST送信してみる(Form送信との比較も) - クモのようにコツコツと
Node.jsのWebサーバ構築方法はこちら。
※参考:Express事始め(インストール〜ハローワールドまで) - クモのようにコツコツと
※参考:【Express】静的HTMLファイルの表示(res.sendFile()、express.static()) - クモのようにコツコツと
Expressインストール
「express_api_test」というフォルダを作ってcd
コマンドで移動。
cd /(フォルダのパス)/express_api_test
npmのpackage.jsonを作成
npm init -y
experssインストール
npm install express --save
index.jsを作成
const express = require('express'); const app = express(); app.use(express.static('public')); app.get('/', (req, res) => { // es.sendFile(__dirname + '/public/index.html'); }); app.listen(3000, () => { console.log('Start server port:3000'); });
app.use(express.static('public'))
のpublic
部分をページに表示する。
静的なファイルを追加する
「public」フォルダを作って、静的なHTMLファイルを入れる。「index.html」とjsフォルダの中に「post_fetch.js」。
この記事の時に作ったファイル一式ね。この時はjsonplaceholderと通信している。
※参考:【JS】Fetch APIでPOST送信してみる(Form送信との比較も) - クモのようにコツコツと
サーバ上の修正を常時監視したいのでnodemonでindex.jsを起動する。
nodemon index.js
ブラウザでローカルホスト(ポート番号3000)表示すると…
http://localhost:3000/
やた!ページが表示された!
body-parserとは
ブラウザからのFormのデータを受け取るためには「body-parser」というモジュールを使う。
Node.js body parsing middleware.
Parse incoming request bodies in a middleware before your handlers, available under the req.body property.
Node.jsボディ解析ミドルウェア。 ハンドラーの前にミドルウェアで受信リクエスト本文を解析します。req.bodyプロパティで利用できます。
基本的な使い方
※参考:body-parser で フォームからの POST データを受け取る方法 - body-parser - Node.js 入門
FormだけでなくFetch APIのJSONデータも受け取れそう!
※参考:body-parser で JSON 形式の HTTP リクエストを受け取る方法 - body-parser - Node.js 入門
※参考:FetchAPIでHTMLからNode.jsに非同期でJSONパラメータを送る | 株式会社ブリッツゲート
自分的にはページ遷移やリロードをしないFetch APIの活用に興味があるため、こちらも体験したい。
body-parserインストール
何は無くともインストール
npm install body-parser
package.jsonを確認。入ってる!
"dependencies": { "body-parser": "^1.19.0", "express": "^4.17.1" }
index.jsにインポートする。
const bodyParser = require('body-parser');
Form送信の設定
formタグ修正
まずformタグを修正
<form method="post" action="/form"> <input type="text" name="name" size="30" maxlength="30"> <input type="submit" value="送信"> </form>
前回、action
属性がjsonplaceholderのURLだったが、今回はページの下層/form
に送信する。
bodyParser.urlencoded()
次にindex.jsでformとのAPI通信を設定する。
const urlencodedParser = bodyParser.urlencoded({ extended: false });
- 変数
urlencodedParser
の引数でbodyParser.urlencoded()
を実行(引数は連想配列でextended
キーをfalse
に)
bodyParser.urlencoded()
はURLエンコードからbody情報だけを抜き出すメソッドのようだ。
Returns middleware that only parses urlencoded bodies and only looks at requests where the Content-Type header matches the type option. This parser accepts only UTF-8 encoding of the body and supports automatic inflation of gzip and deflate encodings.
URLエンコードされた本文のみを解析し、Content-Typeヘッダーがタイプオプションと一致するリクエストのみを確認するミドルウェアを返します。 このパーサーは本文のUTF-8エンコーディングのみを受け入れ、gzipおよびdeflateエンコーディングの自動インフレーションをサポートします。
urlencoded()
の引数の中はオプション
{ extended: false }
extended
オプションは拡張オプションでfalse
にするとクエリ文字列ライブラリにに変換されると。
The extended option allows to choose between parsing the URL-encoded data with the querystring library (when false) or the qs library (when true). The "extended" syntax allows for rich objects and arrays to be encoded into the URL-encoded format, allowing for a JSON-like experience with URL-encoded. For more information, please see the qs library.
拡張オプションを使用すると、URLエンコードされたデータをクエリ文字列ライブラリ(falseの場合)またはqsライブラリ(trueの場合)のどちらで解析するかを選択できます。 「拡張」構文により、リッチオブジェクトと配列をURLエンコード形式にエンコードできるため、URLエンコードされたJSONのようなエクスペリエンスを実現できます。 詳細については、qsライブラリを参照してください。
formのAPI設定
次はformのAPI設定
app.post('/form', urlencodedParser, (req, res) => { console.log(req.body); const name = req.body.name; console.log('name->' + name); res.send('こんにちは!' + name + 'さん'); });
app.post()
を実行。第一引数はパス/form
、第二引数でurlencodedParser
実行、第三引数は無名関数- 無名関数の第一引数はリクエスト
req
、第二引数はレスポンスres
- コンソールでリクエストのボディ情報
req.body
表示 - 変数
name
でボディ情報のname
キーの値を取得 - コンソールで
name
も表示 res.send()
でテキスト情報「こんにちは〇〇さん」のレスポンスを返す
app.post()
はPOST送信の指定パスにルーティングするメソッド
Routes HTTP POST requests to the specified path with the specified callback functions.
指定されたコールバック関数を使用して、HTTP POST要求を指定されたパスにルーティングします。
res.send()
はこちらの記事でも触れたように、いろいろなレスポンスが返せる便利メソッド。
※参考:【Express】静的HTMLファイルの表示(res.sendFile()、express.static()) - クモのようにコツコツと
第一引数でformタグのaction属性と同じ/form
を指定し、第二引数でurlencodedParser
を実行する。第三引数でformからきたnameの値を抜き出して「こんにちは〇〇さん」というテキストを返す。
Fetch APIの通信設定
次はFetch APIの設定をしてみる。
Fetch API設定の変更
まず、フロントエンド側のJSコード(post_fetch.js)のFetch API設定を修正
const fetchForm = document.querySelector('.fetchForm input'); const btn = document.querySelector('.btn'); const url = '/fetch';
- 変数
fetchForm
をformタグではなくinputタグに - 変数
url
を/fetch
に
inputタグにしたのはinputタグの値をJSONデータ自体を送りたかったため。(forからのbody情報だとうまくいかなかった。。)
また、変数url
は先ほどのformタグと同様jsonplaceholderのURLだったが下層の/fetch
に変更した。
次にpostFetch()
のFetch APIの設定を変更
const postFetch = () => { const formData = { name: fetchForm.value }; fetch(url, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(formData) }).then((response) => { if(!response.ok) { console.log('error!'); } console.log('ok!'); console.log(response); return response.text(); }).then((data) => { console.log(data); alert(data); }).catch((error) => { console.log(error); }); };
- 変数
formData
で連想配列を作成。name
キーにinputタグの値を入れる fetch()
のオプションm、headers
に'Content-Type
がJSONデータと設定
body
にJSON.stringify()
で連想配列をJSONデータに変換して送信- 一つ目の
then()
、レスポンスはJSONではなくテキストresponse.text()
で受け取る - 二つ目の
then()
、レスポンスをアラートに表示
全体的にこちらの記事でやったように、formデータではなくJSONデータで送信する方法に書き換えた。
※参考:【JS】Fetch APIを使ってJSON ServerにCRUDする - クモのようにコツコツと
また、レスポンスをresponse.text()
にしたのは、後述するようにindex.jsのAPI設定で先程のformと同様JSONではなく「こんにちは〇〇さん」というテキストを返すため。
なお、最後のイベント設定は変わらない。送信ボタンを押した時に発火。
btn.addEventListener('click', postFetch, false);
bodyParser.json()
次に、index.jsのAPI通信を設定。
const jsonParser = bodyParser.json();
- 変数
jsonParser
でbodyParser.json()
を実行
bodyParser.json()
はJSONを解析するメソッド。
Returns middleware that only parses json and only looks at requests where the Content-Type header matches the type option. This parser accepts any Unicode encoding of the body and supports automatic inflation of gzip and deflate encodings.
jsonの解析のみを行い、Content-Typeヘッダーがタイプオプションと一致するリクエストのみを確認するミドルウェアを返します。 このパーサーは、本文のUnicodeエンコーディングを受け入れ、gzipおよびdeflateエンコーディングの自動インフレーションをサポートします。
Fetch API設定
次にFetch APIの送受信設定。
app.post('/fetch', jsonParser, (req, res) => { console.log(req.body); const name = req.body.name; console.log('name->' + name); res.send('こんにちは!' + name + 'さん'); });
app.post()
の第一引数のパスを/fetch
に- 第二引数で
jsonParser
を実行 - 第三引数のリクエスト、レスポンス設定は先程のformの処理と同じ
パス(/fetch
)と実行するメソッド(jsonParser
)以外は変わらない。
動作確認
formの挙動
作ったものの挙動
ブラウザ(localhost:3000)のフォーム
まずは上のformタグに「孫悟空」と入力して「送信」すると…
ページが遷移(localhost:3000/form)して「こんにちは!孫悟空さん」と表示された!
Dev-toolsの「Network」タブで「form」の内容を確認する。
「Headers」の下の方「Form Data」nameキーの「孫悟空」が送信されている。
「Response」にも「こんにちは!孫悟空さん」が表示されている。
Node環境(index.js)のコンソールにも送信されたデータが表示されている。
[Object: null prototype] { name: '孫悟空' } name->孫悟空
このname「孫悟空」を抜き出してテキストに入れ込んで返したということ!
Fetch APIの挙動
次に下のフォームに「ベジータ」と入れて送信。
「こんにちは!ベジータさん」のアラートが表示された!Fetch APIなのでページ遷移しない♪
Dev-toolsの「Network」で「fetch」を確認する。
「Headers」の下の方、JSON形式でnameキーの値ベジータが送信されている。
「Response」を見ると「こんにちは!ベジータさん」のテキストが返されている。
「Console」にはレスポンスとテキスト「こんにちは!ベジータさん」が表示されている。
レスポンスは階層が深く膨大だがここからテキストだけが抽出できている。
Node環境(index.js)のコンソールにも送信されたデータが表示されている。
{ name: 'ベジータ' } name->ベジータ
コード全体
作ったものこちら
index.html
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <title>ExpressにPOST送信(Form & Fetch)</title> </head> <body> <section> <h1>あなたのお名前なんて〜の?</h1> <p>Formで答える</p> <form method="post" action="/form"> <input type="text" name="name" size="30" maxlength="30"> <input type="submit" value="送信"> </form> <p>Fetchで答える</p> <form class="fetchForm"> <input type="text" name="name" size="30" maxlength="30" class="name"> <input type="button" value="送信" class="btn"> </form> </section> <script src="js/post_fetch.js"></script> </body> </html>
post_fetch.js
const fetchForm = document.querySelector('.fetchForm input'); const btn = document.querySelector('.btn'); const url = '/fetch'; const postFetch = () => { const formData = { name: fetchForm.value }; fetch(url, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(formData) }).then((response) => { if(!response.ok) { console.log('error!'); } console.log('ok!'); console.log(response); return response.text(); }).then((data) => { console.log(data); alert(data); }).catch((error) => { console.log(error); }); }; btn.addEventListener('click', postFetch, false);
index.js
const express = require('express'); const bodyParser = require('body-parser'); const app = express(); app.use(express.static('public')); // Form設定 const urlencodedParser = bodyParser.urlencoded({ extended: false }); app.post('/form', urlencodedParser, (req, res) => { console.log(req.body); const name = req.body.name; console.log('name->' + name); res.send('こんにちは!' + name + 'さん'); }); // Fetch API設定 const jsonParser = bodyParser.json(); app.post('/fetch', jsonParser, (req, res) => { console.log(req.body); const name = req.body.name; console.log('name->' + name); res.send('こんにちは!' + name + 'さん'); }); app.listen(3000, () => { console.log('Start server port:3000'); });
GitHub
※参考:GitHub - ryo-i/express_body_parser: 【Express】body-parserでFetch API(およびForm)のPOST送信を受け取る
最後に
ということで、FormタグやFetch APIから送信されたデータをbody-parserで受け取って、「こんにちは!○○さん」というテキストにして返しました!
ユーザーから見たらなんでもない挙動なんですが、自分としてはこの動きがブラウザ 側だけでなくサーバ(Node環境)とのやり取りを経て実現できていることに大きな意義がありました!
また、formタグだけでなくページ遷移しないFetch APIの非同期通信ともやり取りできてよかったです♪
次はブラウザから送られたデータをサーバ(Node環境)からデータベース(MySQL)にCRUD処理して、さらにその結果をブラウザに表示する、という体験に入って行きたく思います。
それではまた!
※参考:Node.js / Expressを習得するためにやったことまとめ
qiita.com