diff --git a/public/index.html b/public/index.html new file mode 100644 index 0000000..3257912 --- /dev/null +++ b/public/index.html @@ -0,0 +1,122 @@ + + + + + + ๋ฐฉ๋ช…๋ก + + + +
+

๐Ÿ“– ๋ฐฉ๋ช…๋ก

+

ํ•œ ์ค„ ๋‚จ๊ธฐ๊ณ  ๊ฐ€์„ธ์š”. (Postgres ์— ์ €์žฅ๋ฉ๋‹ˆ๋‹ค)

+
+ + +
+ +
+
๋ถˆ๋Ÿฌ์˜ค๋Š” ์ค‘โ€ฆ
+
+ + + + diff --git a/src/db.js b/src/db.js index 0c5aec4..4db9186 100644 --- a/src/db.js +++ b/src/db.js @@ -13,3 +13,32 @@ export async function pingDb() { ); return rows[0]; } + +// --- ๋ฐฉ๋ช…๋ก(guestbook) --- +// ํ…Œ์ด๋ธ”์€ search_path์— ๊ณ ์ •๋œ ๋ณธ์ธ schema์— ์ƒ์„ฑ๋œ๋‹ค(schema ์ ‘๋‘์–ด ๋ถˆํ•„์š”). +export async function initGuestbook() { + await pool.query(` + create table if not exists guestbook ( + id bigint generated always as identity primary key, + name text not null, + message text not null, + created_at timestamptz not null default now() + ) + `); +} + +export async function listMessages(limit = 100) { + const { rows } = await pool.query( + "select id, name, message, created_at from guestbook order by id desc limit $1", + [limit] + ); + return rows; +} + +export async function addMessage(name, message) { + const { rows } = await pool.query( + "insert into guestbook (name, message) values ($1, $2) returning id, name, message, created_at", + [name, message] + ); + return rows[0]; +} diff --git a/src/server.js b/src/server.js index e94230a..46a7508 100644 --- a/src/server.js +++ b/src/server.js @@ -1,10 +1,16 @@ -// ์ตœ์†Œ Express ์„œ๋ฒ„ โ€” /healthz, /db, /s3 ๋กœ ์—ฐ๊ฒฐ ํ™•์ธ. +// Express ์„œ๋ฒ„ โ€” ๋ฐฉ๋ช…๋ก(guestbook) ์›น์‚ฌ์ดํŠธ + ์—ฐ๊ฒฐ ํ™•์ธ์šฉ /healthz, /db, /s3. import express from "express"; +import { fileURLToPath } from "node:url"; +import { dirname, join } from "node:path"; import { config } from "./config.js"; -import { pingDb } from "./db.js"; +import { pingDb, initGuestbook, listMessages, addMessage } from "./db.js"; import { pingS3 } from "./s3.js"; +const __dirname = dirname(fileURLToPath(import.meta.url)); + const app = express(); +app.use(express.json()); +app.use(express.static(join(__dirname, "..", "public"))); app.get("/healthz", (_req, res) => res.json({ ok: true })); @@ -24,10 +30,37 @@ app.get("/s3", async (_req, res) => { } }); -app.get("/", (_req, res) => - res.json({ name: "sample", endpoints: ["/healthz", "/db", "/s3"] }) -); - -app.listen(config.port, "0.0.0.0", () => { - console.log(`sample listening on :${config.port}`); +// --- ๋ฐฉ๋ช…๋ก API --- +app.get("/api/messages", async (_req, res) => { + try { + res.json({ ok: true, messages: await listMessages() }); + } catch (e) { + res.status(500).json({ ok: false, error: String(e.message || e) }); + } +}); + +app.post("/api/messages", async (req, res) => { + try { + const name = String(req.body?.name ?? "").trim(); + const message = String(req.body?.message ?? "").trim(); + if (!name || !message) { + return res + .status(400) + .json({ ok: false, error: "name ๊ณผ message ๋Š” ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค." }); + } + if (name.length > 40 || message.length > 500) { + return res + .status(400) + .json({ ok: false, error: "์ด๋ฆ„์€ 40์ž, ๋ฉ”์‹œ์ง€๋Š” 500์ž ์ด๋‚ด." }); + } + res.json({ ok: true, message: await addMessage(name, message) }); + } catch (e) { + res.status(500).json({ ok: false, error: String(e.message || e) }); + } +}); + +// ์•ฑ ์‹œ์ž‘ ์ „์— ํ…Œ์ด๋ธ” ๋ณด์žฅ ํ›„ ๋ฆฌ์Šจ. +await initGuestbook(); +app.listen(config.port, "0.0.0.0", () => { + console.log(`guestbook listening on :${config.port}`); });