1. Fastify、AJAX とは
- FastifyはAPIサーバーの構築に非常に適した高性能なNode.jsフレームワークです
- AJAXとは、Asynchronous JavaScript and XMLの略称で、Web アプリケーションでデータを非同期的に転送する通信手法のことを指します
2. 内容:
静的HTMLファイルをFastifyを用いてホスティングします。さらにスクリプト内のロジックをAJAXを用いてバックエンドに移行することを実現できたので、その過程・内容についてまとめます。
題材はAtCoderの問題 ABC053Aを簡易なwebアプリにしたものです。
3. Fastify のインストール・実行・閲覧
Node.jsがインストールされていることを確認した上で、Fastifyをinstallします。
インストール
npm install fastify
実行
node server.js
閲覧
4. 元の静的HTML全体像
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>abc053a</title>
</head>
<body>
<h1>abc053a</h1>
<p>
現在のレートxが1200未満かどうかで、参加するコンテスト(ABC/ARC)を選択し出力する。
</p>
<form id="squareForm">
<label for="N">Select your rate:</label>
<input type="range" name="N" id="N" min="0" max="4000" value="1200" required>
<span id="rateValue">1200</span> <!-- Span to display selected value -->
<br>
<input type="submit" value="Submit">
</form>
<p id="output"></p>
<script>
// Get elements
var slider = document.getElementById('N');
var output = document.getElementById('rateValue');
// Display the default value
output.innerHTML = slider.value;
// Update the current slider value (each time you drag the slider handle)
slider.oninput = function () {
output.innerHTML = this.value;
};
document.getElementById('squareForm').addEventListener('submit', function (event) {
event.preventDefault(); // Prevent default form submission
var N = parseInt(document.getElementById('N').value);
////////////////////////////バックエンドに移行される部分/////////////////////////////////////
var ANS;
if (N < 1200) {
ANS = "ABC";
} else {
ANS = "ARC";
}
////////////////////////////////////////////////////////////////////////////////////////////
document.getElementById('output').innerText = "RATE: " + N + "\nCONTEST: " + ANS;
});
</script>
</body>
</html>
5. Fastifyで静的HTMLファイルをホスティングする
階層構造
project-root
├── public
│ └── index.html : 元htmlをそのままコピペするだけ。
├── server.js
├── package.json
server.js
// server.js
const fastify = require('fastify')({ logger: true })
const path = require('path')
const fastifyStatic = require('@fastify/static')
/////////////////public/index.html設置に伴いこの部分が追加される////////////////////
// Register the static plugin
fastify.register(fastifyStatic, {
root: path.join(__dirname, 'public'),
prefix: '/', // optional: default '/'
})
/////////////////////////////////////////////////////////////////////////////////
// Start the server
const start = async () => {
try {
await fastify.listen({ port: 3000 })
console.log('Server is running at http://localhost:3000')
} catch (err) {
fastify.log.error(err)
process.exit(1)
}
}
start()
6. フロントエンドに書かれたロジックを AJAX を用いてバックエンドに移行
public/index.html
<script>
// Get elements
var slider = document.getElementById('N');
var output = document.getElementById('rateValue');
// Display the default value
output.innerHTML = slider.value;
// Update the current slider value (each time you drag the slider handle)
slider.oninput = function () {
output.innerHTML = this.value;
};
document.getElementById('squareForm').addEventListener('submit', function (event) {
event.preventDefault(); // Prevent default form submission
var N = parseInt(document.getElementById('N').value);
////////////////////////サーバーとの送受信をメソッドを記載//////////////////////////
////////////////////HTTP POSTメソッドを使用し値をrateというキーで送信。//////////////
// Make an AJAX request to the backend
fetch('/api/getContest', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ rate: N })
})
///////////////////////サーバーからの応答をJSON形式にパース/////////////////////////
.then(response => response.json())
.then(data => {
document.getElementById('output').innerText = "RATE: " + data.rate + "\nCONTEST: " + data.contest;
})
.catch(error => console.error('Error:', error));
//////////////////////////////////////////////////////////////////////////////
});
</script>
server.js
// server.js
const fastify = require('fastify')({ logger: true })
const path = require('path')
const fastifyStatic = require('@fastify/static')
// Register the static plugin
fastify.register(fastifyStatic, {
root: path.join(__dirname, 'public'),
prefix: '/', // optional: default '/'
})
///////////////////////////////////////////////////////////////
// Define the new endpoint
fastify.post('/api/getContest', async (request, reply) => {
const { rate } = request.body
let contest
if (rate < 1200) {
contest = 'ABC'
} else {
contest = 'ARC'
}
return { rate, contest }
})
///////////////////////////////////////////////////////////////
// Start the server
const start = async () => {
try {
await fastify.listen({ port: 3000 })
console.log('Server is running at http://localhost:3000')
} catch (err) {
fastify.log.error(err)
process.exit(1)
}
}
start()
7. 全体の流れ
- クライアントが /api/getContest エンドポイントに対して POST リクエストを送信します
- サーバーは request.body から rate を取得します
- rate の値に基づいて contest を設定します
- { rate, contest } のオブジェクトをレスポンスとしてクライアントに返します
今回はFastify で 静的HTMLファイルのフロントエンドに書かれたロジックを AJAX を用いてバックエンドに移行することを通じて、バックエンドとの送受信の全体像が把握できました。
AJAXを用いる他のタスク(データベース操作、サーバーサイドの計算や処理、APIとの連携、など)も同様のアプローチで組めるはずです。