掲示板のサーバーも(おそらく)今回で完成し、掲示板の骨子は完成します。
では、やっていきましょう。
バックエンド側のコード(Node.js)
const express = require('express'); const cors = require('cors'); const app = express(); const PORT = 3000; app.use(cors()); app.use(express.json()); let messages = []; app.get('/api/messages', (req, res) => { res.json(messages); }); app.post('/api/messages', (req, res) => { console.log('POST受信:', req.body); const { name, comment } = req.body; if (!name || !comment) { return res.status(400).json({ error: '名前を書く。コメントを書く。両方やらなくっちゃあならないところがユーザーのつらいところだな' }); } const newMessage = { name, comment }; messages.push(newMessage); res.status(201).json(newMessage); }); app.listen(PORT, () => { console.log(`サーバーがポート${PORT}で稼働中`); });
この多くはAPIを作ったときに学習していますね。
ここに書かれていることは簡単に書いていくことにします。
って、よく見たら一行見たことがないものがありますね。
const cors = require('cors');
これ、とりあえず先生に教えてもらったコードを動かそうとしたけど動かせなかった原因になったやつですね。
html-css-javascript.hatenadiary.com
ではそのCORSがなんなのか見ていきます。
CORSとは
Cross-Origin Resource Sharing(クロス・オリジン・リソース・シェアリング)の略です。
わかりましたね、はい、では次いきましょう。
というにはよくわからない言葉なので意味を調べていきましょう。
Origin(オリジン)とは、データの出どころです。
Originはスキーム、ホスト、ポート番号の組み合わせです。
ポート番号はすでに説明しましたが、スキームとホストはまだ馴染みない言葉です。
以下のアドレスを開いていると想定してみてください。
http://localhost:5500/index.html
httpがスキーム、localhostがホスト、5500がポート番号です。
httpとはHyperText Transfer Protocolです。
つまりハイパーテキストの転送の方式です。
ハイパーテキストというのはHTMLのコードを指します。
HTMLのコードでは、文字にリンクを付与したり、画像を差し込んだり、オーディオを差し込んだりできますが、ああいうことを指示するコード全体をハイパーテキストと呼びます。
その通信プロトコル(通信に使われる共通言語)がhttpということになります。
スキームはhttp,httpsがありますが、httpsのほうがセキュリティ的に高いので、基本こちらを使います。
httpは今は古いサイトでしか使われていません。
ホストは、(今のところ)サーバーということでいいです。
今はローカルで動かしていますので、localhostという名前にしてあります。
ポート番号はどこかの記事でも書いた通り、データの宛先の部屋番号みたいなものです。
なのでCross-Originとはデータの出どころをまたぐもの、ということになります。
RはResorce(リソース、情報)、SはSharing(分配)です。
つなげて言うと、「異なるオリジンから来たリクエストに、データを共有していいかどうかを判別する」ものです。
もっと砕けて言うと「出どころが分からないところからデータをくれというリクエストが来たけど、渡していいのか判別する」ものです。
これが合っていなければ、データの受け渡しは行われません。
私が最初にいきなり躓いたところです。
これがCORSになります。
さて、CORSの謎は解けましたので、いっきに進められますね。
説明文はそのままコードブロックのコメントに書いていきます。
const express = require('express'); // expressを使えるようにする const cors = require('cors'); //CORSを使えるようにする const app = express(); //expressをオブジェクト化 const PORT = 3000; //ポート番号に3000にする app.use(cors()); //CORSを有効化 app.use(express.json()); // JSON形式のリクエストを扱えるようにする let messages = []; //投稿を順番に保存する配列 app.get('/api/messages', (req, res) => { res.json(messages); //配列の中身をJSON形式で返す });
次です。
app.post('/api/messages', (req, res) => { console.log('POST受信:', req.body); const { name, comment } = req.body; if (!name || !comment) { return res.status(400).json({ error: '名前とコメントは必須だってわかっていたのに…' }); } const newMessage = { name, comment }; messages.push(newMessage); res.status(201).json(newMessage); });
app.post('/api/messages', (req, res) => {
ですから、フォーム側から送られてきたデータはreq、サーバーから送られてきたデータはresが引数として使われることになります。
ここからは先ほどと同じようにコードブロック内のコメントアウトで簡単に説明していきます。
app.post('/api/messages', (req, res) => { console.log('POST受信:', req.body); // POSTされたデータを確認 const { name, comment } = req.body; //ボディからnameとcommentを取り出す if (!name || !comment) { //nameもしくはcommentが空欄だった場合 return res.status(400).json({ error: '名前とコメントは必須だってわかっていたのに…' }); //エラーを返す ※少し長いので後述 } const newMessage = { name, comment }; messages.push(newMessage); res.status(201).json(newMessage); });
ボディの意味はこちらの記事に記載しているので、わからない方はどうぞ。
※statusとは、そのままresのステータス、状態だと思ってかまいません。
そのステータスが400を指しているということは、このresは正しくないということを示します。
正しい場合は基本200番台が出てきます。
特に作成成功の場合は201番が出ます。
.json({ error: '名前とコメントは必須だってわかっていたのに…' }
これはそのまんま、JavaScript形式で書かれたデータをJSON形式にしてクライアント側に送ります。
ちなみにJavaScript形式の中の{}の中だけを書いたものをオブジェクトリテラルと呼ぶので、それも覚えておくといいでしょう。
さて、この結果をreturnで返すわけですが、返す先はフロントエンドのJavaScriptです。
Script.jsのファイルの中で、以下のようなコードがありました。
if (!res.ok) throw new Error('投稿一覧の取得に失敗しました');
返されたデータはここに送られます。
400番台は!res.okに含まれますので、このコードに従ってthrow new Error('メッセージ')が実行されることになります。
ここについてはフロントエンドの記事で説明していますのでご参照ください。
クラスとかインスタンスとかちょっと最初は理解が難しいところついて、ほかとは違う説明もしてあるので、理解があいまいだなという人の参考にもなると思います。
で、なんでサーバー側でステータスを審査して、その結果をクライアント側に渡すのかというと、クライアント側で審査するのがいろいろと不都合だからです。
クライアント側をいじられるかもしれないというセキュリティの問題もありますし、クライアントってPCやスマホみたいにいろんなものがあったりもします。
そうすると信頼できる審査はサーバーということになります。
なのでここはサーバー側で審査します。
さて、次行きます。
もう少しで終わりです。
const newMessage = { name, comment }; //名前とコメントのオブジェクト作成 messages.push(newMessage); //作成したオブジェクトを配列の最後尾に追加 res.status(201).json(newMessage); //作成成功(201)をフロントに送信
ラストです。
app.listen(PORT, () => { console.log(`サーバーがポート${PORT}で稼働中`); });
これは「掲示板のサーバーを作る②APIを作る」でも書いたように、サーバーの立ち上げです。
「電子レンジみたいにいろいろなことを設定してから起動する」という順番ですので、記述する場所としては最後になります。
html-css-javascript.hatenadiary.com
おわりに
掲示板作成ためのコードにつきましては、ここで終了になります。
最後のほうはほとんどコメントアウトでの簡易的な説明でしたが、どれもこれまでの記事で解説したものなので、わからないものがあれば右カラムの検索で記事内を検索して頂ければと思います。
さて。
一つ一つの意味は見えてきましたが、フロントエンドとバックエンドのデータのやり取りの動きなどについて、まだ少しあいまいなところがあるように思えます。
例えば
const newMessage = { name, comment }; messages.push(newMessage);
と
function showPostedMessage(message) { const postedDiv = document.getElementById('posted'); const newMessage = document.createElement('div'); newMessage.innerHTML = ` <p><strong>${escapeHTML(message.name)}</strong> さんのコメント:</p> <p>${escapeHTML(message.comment)}</p> <hr> `; postedDiv.prepend(newMessage); }
のような。
書き込む内容をサーバー側からフロント側に送って、それを表示しているですが、パッとみてすぐにわかる、というところまではまだ達していません。
次回はそうしたまとめを書いていこうと思います。