P2B-WEB-2026_2025/block-01/week-01-the_web_under_the_hood/demo/server.ts

136 lines
3.3 KiB
TypeScript

import express from "express"
import fs from "fs/promises"
import { status } from "http-status"
import { createServer as createViteServer } from "vite"
import { injectIntoHtml } from "./src/utils/inject"
import { partials } from "./src/plugins/injectPartials"
const app = express()
const vite = await createViteServer({
server: { middlewareMode: true },
appType: "mpa",
})
app.use(express.urlencoded({ extended: true }))
app.use(express.json())
// Log every incoming request to the terminal
app.use((req, res, next) => {
console.log("\n" + "=".repeat(50))
console.log(`${req.method} ${req.url}`)
console.log("\n-- Headers --")
console.log(req.headers)
if (Object.keys(req.body || {}).length > 0) {
console.log("\n-- Body --")
console.log(req.body)
}
if (Object.keys(req.cookies || {}).length > 0) {
console.log("\n-- Cookies --")
console.log(req.cookies)
}
console.log("=".repeat(50))
next()
})
// Receives the POST: echoes the body back
app.post("/login", async (req, res) => {
const { username, password } = req.body
const base = await fs.readFile("src/partials/form-response.html", "utf-8")
let result = await injectIntoHtml(base, [
...partials,
{
key: "<!--LOGIN_DATA-->",
placement: "replace",
type: "string",
value: JSON.stringify({ username, password }, null, 2),
},
])
res.send(result)
})
// Sets a cookie: shows Set-Cookie header in DevTools
app.get("/set-cookie", (req, res) => {
res.cookie("session", "abc123xyz", {
httpOnly: true,
maxAge: 60 * 60 * 1000, // 1 hour
})
req.next?.()
})
// Shows what cookies the server received
app.get("/show-cookies", async (req, res) => {
const cookieHeader = req.headers["cookie"] || "none"
const base = await fs.readFile("show-cookie.html", "utf-8")
let result = await injectIntoHtml(base, [
...partials,
{
key: "<!--COOKIES-->",
placement: "replace",
type: "string",
value: cookieHeader,
},
])
res.send(result)
})
// Returns JSON: shows Content-Type in action
app.get("/json", (req, res) => {
res.json({
message: "This is a JSON response",
method: req.method,
url: req.url,
headers: req.headers,
})
})
// Delayed response: simulates a slow server
app.get("/delay", (req, res) => {
setTimeout(() => {
req.next?.()
}, 5000)
})
// Demonstrates different status codes
app.get("/status/:code", async (req, res) => {
const code = parseInt(req.params.code)
const base = await fs.readFile("status-code.html", "utf-8")
let result = await injectIntoHtml(base, [
...partials,
{
key: "<!--HTTP_STATUS_CODE-->",
placement: "replace",
type: "string",
value: code.toString(),
occurrence: "all",
},
{
key: "<!--HTTP_STATUS_NAME-->",
placement: "replace",
type: "string",
value: String(status[code as keyof typeof status]),
occurrence: "all",
},
{
key: "<!--HTTP_HEADERS-->",
placement: "replace",
type: "string",
value: JSON.stringify(req.headers, null, 2),
occurrence: "all",
},
])
res.status(code).send(result)
})
app.use(vite.middlewares)
app.listen(3000, () => {
console.log("Echo server running on http://localhost:3000")
console.log("Watching for requests...\n")
})