{"id":7757,"date":"2026-08-11T07:25:51","date_gmt":"2026-08-10T22:25:51","guid":{"rendered":"https:\/\/www.freelifemakers.org\/wordpress\/?p=7757"},"modified":"2026-08-13T11:09:05","modified_gmt":"2026-08-13T02:09:05","slug":"nextjs-sns-server-1","status":"publish","type":"post","link":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/2026\/08\/11\/nextjs-sns-server-1\/","title":{"rendered":"[nextjs]SNS Server-1(API CRUD)"},"content":{"rendered":"\n<p>\ud83d\udc49\ud83c\udffb SNS Server\ub97c \ub9cc\ub4e4\uc5b4 \ubd05\ub2c8\ub2e4.<br>Let&#8217;s build an SNS server.<\/p>\n\n\n\n<p>\ud83d\udc49\ud83c\udffb \uc6f9\uc0ac\uc774\ud2b8 \ud654\uba74 \uc774\uc804\uc5d0 CRUD API\ubd80\ubd84\uc744 \uba3c\uc800 \uad6c\ud604\ud574 \ubd05\ub2c8\ub2e4.<br>We will implement the CRUD API first, before working on the website interface.<\/p>\n\n\n\n<p>\ud83d\udcc1 \uc804\uccb4 \ud504\ub85c\uc81d\ud2b8 \uad6c\uc870 \/ Project Structure<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>myapp11\/ (Root Directory)\n\u251c\u2500\u2500 \ud83d\udcc1 app\/                    # Next.js App Router\n\u2502   \u251c\u2500\u2500 \ud83d\udcc1 api\/                \n\u2502   \u2502   \u2514\u2500\u2500 \ud83d\udcc1 posts\/          \n\u2502   \u2502       \u2514\u2500\u2500 \ud83d\udcc4 route.ts    # CRUD API\n\u2502   \u251c\u2500\u2500 \ud83d\udcc4 layout.tsx          \n\u2502   \u251c\u2500\u2500 \ud83d\udcc4 page.tsx            # Main Home\n\u2502   \u2514\u2500\u2500 \ud83d\udcc4 globals.css        \n\u251c\u2500\u2500 \ud83d\udcc1 lib\/                    \n\u2502   \u2514\u2500\u2500 \ud83d\udcc4 db.ts               # SQLite dbconnection(data.sqlite)\n\u251c\u2500\u2500 \ud83d\udcc4 data.sqlite             # Local SQLite Database\n\u2514\u2500\u2500 \ud83d\udcc4 Caddyfile               # Caddy file\n<\/code><\/pre>\n\n\n\n<p>\ud83d\udcc1 Nextjs \ud504\ub85c\uc81d\ud2b8 \uc2dc\uc791 \/ Starting a Next.js project(myapp11)<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>npx create-next-app@latest<\/code><\/pre>\n\n\n\n<p>\ud83d\udcc1 SQLite\uc124\uce58 \/ Installing SQLite<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>cd ~\/myapp11\nnpm install better-sqlite3\nnpm install -D @types\/better-sqlite3<\/code><\/pre>\n\n\n\n<p>\ud83d\udcc1 API\ucf54\ub4dc \uc791\uc131<br>Writing API code<\/p>\n\n\n\n<p>\u2714\ufe0f myapp11\/app\/api\/posts\/route.ts<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\/\/ ~\/myapp11\/app\/api\/posts\/route.ts\nimport db from '@\/lib\/db';\nimport { randomUUID } from 'crypto';\n\nexport async function GET() {\n  \/\/ R - \uc77d\uae30 \/ Read\n  const posts = db.prepare('SELECT * FROM posts ORDER BY created_at DESC').all();\n  return Response.json(posts);\n}\n\nexport async function POST(req: Request) {\n  \/\/ C - \uc0dd\uc131 \/ Create\n  const { content } = await req.json();\n  if (!content) return Response.json({ error: '\ub0b4\uc6a9 \uc5c6\uc74c \/ Content is required' }, { status: 400 });\n\n  const id = randomUUID();\n  db.prepare('INSERT INTO posts (id, content) VALUES (?, ?)').run(id, content);\n\n  const post = db.prepare('SELECT * FROM posts WHERE id = ?').get(id);\n  return Response.json(post);\n}\n\nexport async function PUT(req: Request) {\n  \/\/ U - \uc218\uc815 \/ Update\n  const { id, content } = await req.json();\n  if (!id || !content) {\n    return Response.json({ error: 'id\uc640 content \ud544\uc694 \/ id and content are required' }, { status: 400 });\n  }\n\n  const result = db.prepare('UPDATE posts SET content = ? WHERE id = ?').run(content, id);\n  \n  if (result.changes === 0) {\n    return Response.json({ error: '\ud574\ub2f9 \uae00 \uc5c6\uc74c \/ Post not found' }, { status: 404 });\n  }\n\n  const post = db.prepare('SELECT * FROM posts WHERE id = ?').get(id);\n  return Response.json(post);\n}\n\nexport async function DELETE(req: Request) {\n  \/\/ D - \uc0ad\uc81c \/ Delete\n  const { searchParams } = new URL(req.url);\n  const id = searchParams.get('id');\n  if (!id) return Response.json({ error: 'id \ud544\uc694 \/ You need id' }, { status: 400 });\n\n  db.prepare('DELETE FROM posts WHERE id = ?').run(id);\n  return Response.json({ ok: true });\n}\n<\/code><\/pre>\n\n\n\n<p>\u2714\ufe0f myapp11\/db\/db.ts<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\/\/ ~\/myapp11\/lib\/db.ts\nimport Database from 'better-sqlite3';\nimport path from 'path';\nimport fs from 'fs';\n\nconst dir = path.join(process.cwd());\nconst dbPath = path.join(dir, 'data.sqlite');\n\nconst db = new Database(dbPath);\n\n\/\/ \ud14c\uc774\ube14 \uc0dd\uc131 \/ Create table if it doesn't exist\ndb.exec(`\n  CREATE TABLE IF NOT EXISTS posts (\n    id TEXT PRIMARY KEY,\n    content TEXT NOT NULL,\n    created_at DATETIME DEFAULT CURRENT_TIMESTAMP\n  );\n`);\n\nexport default db;\n<\/code><\/pre>\n\n\n\n<p>\ud83d\udcc1 Nextjs \uc11c\ubc84\uc2e4\ud589 \/ Running the Next.js server<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>npm run dev<\/code><\/pre>\n\n\n\n<p>\ud83d\udcc1 \ub2e4\ub978 \ud130\ubbf8\ub110\uc5d0\uc11c \uae00\uc800\uc7a5 \ubc0f \ubaa9\ub85d \ubcf4\uae30<br>Save posts and view lists from another terminal<\/p>\n\n\n\n<p>\u2714\ufe0f \ud130\ubbf8\ub110\uc5d0\uc11c \uc2e4\ud589\ud569\ub2c8\ub2e4.()<br>Run it in the terminal.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># \uae00 \uc4f0\uae30 \/ Write a Post\n\ncurl -X POST http:\/\/localhost:3000\/api\/posts -H \"Content-Type: application\/json\" -d '{\"content\":\"\uccab \uae00! sqlite\uc5d0 \uc800\uc7a5\ub428\"}'\n\n# \uae00 \ubaa9\ub85d \ubcf4\uae30 \/ View list of posts\ncurl http:\/\/localhost:3000\/api\/posts\n\n# \uae00 \uc218\uc815\ud558\uae30 \/ Edit Post\ncurl -X PUT http:\/\/localhost:3000\/api\/posts -H \"Content-Type: application\/json\" -d '{\"id\":\"a1b2c3d4-...\",\"content\":\"\uc218\uc815\ub41c \ub0b4\uc6a9\/Revised content!\"}'\n\n\n# \uae00 \uc0ad\uc81c \/ Delete post\ncurl -X DELETE \"http:\/\/localhost:3000\/api\/posts?id=a1b2c3d4-...\"\n<\/code><\/pre>\n\n\n\n<p>1)\uae00\uc4f0\uae30\ub97c \ube0c\ub77c\uc6b0\uc800\uc5d0\uc11c \ud558\ub824\uba74 page.tsx\uc5d0 \uae00 \uc804\uc1a1\ud558\ub294 \ucf54\ub4dc\ub97c \ubcc4\ub3c4\ub85c \ub9cc\ub4e4\uc5b4\uc57c\ud569\ub2c8\ub2e4.<br>To write posts directly in the browser, you need to create separate code in <code>page.tsx<\/code> to submit the content.<\/p>\n\n\n\n<p>\u2714\ufe0f \ube0c\ub77c\uc6b0\uc800\uc5d0\uc11c \uae00 \ubaa9\ub85d \ubcf4\uae30<br>View the list of posts in the browser<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"800\" height=\"796\" src=\"https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2026\/08\/myapp11-5-jpg.jpg\" alt=\"\" class=\"wp-image-7831\" srcset=\"https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2026\/08\/myapp11-5-jpg.jpg 800w, https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2026\/08\/myapp11-5-jpg-300x300.jpg 300w, https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2026\/08\/myapp11-5-jpg-150x150.jpg 150w, https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2026\/08\/myapp11-5-jpg-768x764.jpg 768w, https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2026\/08\/myapp11-5-jpg-400x398.jpg 400w\" sizes=\"auto, (max-width: 800px) 100vw, 800px\" \/><figcaption class=\"wp-element-caption\">API<\/figcaption><\/figure>\n","protected":false},"excerpt":{"rendered":"<p>\ud83d\udc49\ud83c\udffb SNS Server\ub97c \ub9cc\ub4e4\uc5b4 \ubd05\ub2c8\ub2e4.Let&#8217;s build an SNS server. \ud83d\udc49\ud83c\udffb \uc6f9\uc0ac\uc774\ud2b8 \ud654\uba74 \uc774\uc804\uc5d0 CRUD API\ubd80\ubd84\uc744 \uba3c\uc800 \uad6c\ud604\ud574 \ubd05\ub2c8\ub2e4.We will implement the CRUD API first, before working on the website interface. \ud83d\udcc1 \uc804\uccb4 \ud504\ub85c\uc81d\ud2b8 \uad6c\uc870 \/ Project Structure \ud83d\udcc1 Nextjs \ud504\ub85c\uc81d\ud2b8 \uc2dc\uc791 \/ Starting a Next.js project(myapp11) \ud83d\udcc1 SQLite\uc124\uce58 \/ Installing SQLite \ud83d\udcc1 API\ucf54\ub4dc \uc791\uc131Writing API [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[27,1,7],"tags":[],"class_list":["post-7757","post","type-post","status-publish","format-standard","hentry","category-nextjs","category-uncategorized","category-website","missing-thumbnail"],"_links":{"self":[{"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/posts\/7757","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/comments?post=7757"}],"version-history":[{"count":46,"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/posts\/7757\/revisions"}],"predecessor-version":[{"id":7839,"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/posts\/7757\/revisions\/7839"}],"wp:attachment":[{"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/media?parent=7757"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/categories?post=7757"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/tags?post=7757"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}