{"id":13186,"date":"2026-10-31T09:23:32","date_gmt":"2026-10-31T00:23:32","guid":{"rendered":"https:\/\/www.freelifemakers.org\/wordpress\/?p=13186"},"modified":"2026-10-31T12:09:11","modified_gmt":"2026-10-31T03:09:11","slug":"nextjs-sns-server-52-2","status":"publish","type":"post","link":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/2026\/10\/31\/nextjs-sns-server-52-2\/","title":{"rendered":"[nextjs]SNS Server-52+(myapp62+)[DB \uc5b4\ub311\ud130\/DB Adapter]"},"content":{"rendered":"\n<p>\ud83d\udc49\ud83c\udffb DB\uc5b4\ub381\ud130 \ubd80\ubd84 \ucd94\uac00 \uc124\uba85\uc785\ub2c8\ub2e4.<br>Here is some additional information regarding the DB adapter component.<\/p>\n\n\n\n<p>\ud83d\udcc1 \ud504\ub85c\uc81d\ud2b8 \ub514\ub809\ud1a0\ub9ac \uad6c\uc870 \/ Project Directory Structure<\/p>\n\n\n\n<pre class=\"wp-block-code\" style=\"font-size:14px\"><code>myapp62\/\n\u251c\u2500\u2500 app\/                          \n\u2502   \u251c\u2500\u2500 layout.tsx              \n\u2502   \u251c\u2500\u2500 page.tsx                  \n\u2502   \u251c\u2500\u2500 globals.css              \n\u2502   \u251c\u2500\u2500 favicon.ico\n\u2502   \u2514\u2500\u2500 api\/                      \n\u2502       \u2514\u2500\u2500 users\/                \n\u2502           \u251c\u2500\u2500 route.ts          \n\u2502           \u2514\u2500\u2500 &#91;id]\/             \n\u2502               \u2514\u2500\u2500 route.ts      \n\u2502\n\u251c\u2500\u2500 lib\/                         \n\u2502   \u2514\u2500\u2500 db\/\n\u2502       \u251c\u2500\u2500 adapter.ts\n\u2502       \u251c\u2500\u2500 index.ts\n\u2502       \u2514\u2500\u2500 drivers\/\n\u2502           \u251c\u2500\u2500 sqlite.ts\n\u2502           \u2514\u2500\u2500 mysql.ts\n\u2502\n\u251c\u2500\u2500 data.sqlite                   # SQLite DB \n\u251c\u2500\u2500 data.sqlite-wal               # WAL \ub85c\uadf8 (\uc784\uc2dc) \/ WAL Log (Temporary)\n\u251c\u2500\u2500 data.sqlite-shm               # \uacf5\uc720 \uba54\ubaa8\ub9ac (\uc784\uc2dc) \/ Shared Memory (Temporary)\n\u251c\u2500\u2500 Caddyfile                     # https \uc124\uc815 (duckdns) \/ HTTPS setup (DuckDNS)\n\u251c\u2500\u2500 next.config.ts\n\u251c\u2500\u2500 package.json\n\u2514\u2500\u2500 tsconfig.json<\/code><\/pre>\n\n\n\n<p>\u2714\ufe0f mysql \uc124\uce58 \uc704\uce58 \/ MySQL installation location<\/p>\n\n\n\n<pre class=\"wp-block-code\" style=\"font-size:14px\"><code>% which mysql\n\/opt\/homebrew\/bin\/mysql<\/code><\/pre>\n\n\n\n<p>1)\uc704\uc758 \uacbd\uc6b0\ub294 \ub9e5OS\uc758 M3\uc778\uacbd\uc6b0 \uc785\ub2c8\ub2e4.<br>The case above applies to the M3 version on macOS.<\/p>\n\n\n\n<p>2)\uc6b4\uc601\uccb4\uc81c\ub9c8\ub2e4 \uc124\uce58 \uacbd\ub85c\uac00 \ub2e4\ub97c \uc218 \uc788\uc2b5\ub2c8\ub2e4.<br>The installation path may vary depending on the operating system.<\/p>\n\n\n\n<p>\ud83d\udcc1 DB \uc120\ud0dd \/ Select DB<\/p>\n\n\n\n<p>\u2714\ufe0f lib\/db\/index.ts<\/p>\n\n\n\n<p>&#8212; env.local\uc5d0\uc11c \uc9c0\uc7a5\ub41c \ub370\uc774\ud130\ubca0\uc774\uc2a4\ub97c \uc120\ud0dd\ud558\uace0 \ud574\ub2f9 \uc5b4\ub311\ud130\ub97c \ud638\ucd9c\ud558\ub294 \ubd80\ubd84\uc785\ub2c8\ub2e4.<br>This is the part that selects the database specified in <code>env.local<\/code> and invokes the corresponding adapter.<\/p>\n\n\n\n<pre class=\"wp-block-code\" style=\"font-size:14px\"><code>import type { DbAdapter } from '.\/adapter.ts';\nimport { SqliteAdapter } from '.\/drivers\/sqlite';\nimport { MysqlAdapter } from '.\/drivers\/mysql';<\/code><\/pre>\n\n\n\n<p>1) \uc774 \ubd80\ubd84\uc5d0\uc11c DB\uc5b4\ub381\ud130 \uc778\ud130\ud398\uc774\uc2a4\uc640 \ud574\ub2f9 \ub370\uc774\ud130\ubca0\uc774\uc2a4 \uc5b4\ub311\ud130\ub97c \ud638\ucd9c\ud569\ub2c8\ub2e4.<br>In this section, the DB adapter interface and the corresponding database adapter are invoked.<\/p>\n\n\n\n<p>2) \ud604\uc7ac \uc9c0\uc6d0\ub418\ub294 \ub370\uc774\ud130\ubca0\uc774\uc2a4\ub294 sqlite\uc640 mysql\uc784\uc744 \ud655\uc778 \ud560 \uc218 \uc788\uc2b5\ub2c8\ub2e4. <br>You can see that the currently supported databases are SQLite and MySQL.<\/p>\n\n\n\n<p>&#8212; \uc120\ud0dd\ub41c \ub370\uc774\ud130\ubca0\uc774\uc2a4  \uc5b4\ub311\ud130\ub85c \uac1d\uccb4\ub97c \uc0dd\uc131\ud569\ub2c8\ub2e4.<br>Create an object using the selected database adapter.<\/p>\n\n\n\n<pre class=\"wp-block-code\" style=\"font-size:14px\"><code>... ...\nlet instance: DbAdapter | null = null;\n\nexport function <strong>getDb(): DbAdapter<\/strong> {\n  if (instance) return instance;\n\n  const type = process.env.DB_TYPE || 'mysql';\n\n  if (type === 'mysql') {\n    console.log(`&#91;DB] Using MySQL -> ${process.env.DB_USER}@${process.env.DB_HOST}\/${process.env.DB_DATABASE}`);\n    <strong>instance = new MysqlAdapter();<\/strong>\n  } else {\n    const url = process.env.DATABASE_URL || '.\/data.sqlite';\n    console.log(`&#91;DB] Using SQLite -> ${url}`);\n   <strong> instance = new SqliteAdapter(url);<\/strong>\n  }\n\n  return instance;\n}\n\nexport default getDb;<\/code><\/pre>\n\n\n\n<p>1) MysqlAdapter\uc640 SqliteAdapter\ub294 \ud074\ub798\uc2a4\uc785\ub2c8\ub2e4.<br>MysqlAdapter and SqliteAdapter are classes.<\/p>\n\n\n\n<p>2)DbAdpater\ub294 \uc778\ud130\ud398\uc774\uc2a4\ub85c getDB()\ud568\uc218\uc758 \ud0c0\uc785\uc73c\ub85c \uc0ac\uc6a9\ub429\ub2c8\ub2e4.<br>DbAdapter is an interface used as the return type for the getDB() function.<\/p>\n\n\n\n<p>\ud83d\udcc1 DB \uc0ac\uc6a9 \/ Using a DB<\/p>\n\n\n\n<p>\u2714\ufe0f app\/api\/users\/route.ts<\/p>\n\n\n\n<p>&#8212; \uc120\ud0dd\ub41c \ub370\uc774\ud130\ubca0\uc774\uc2a4\ub97c \uc0ac\uc6a9 \ud560 \ub54c\ub294 \uc544\ub798\uc640 \uac19\uc774 \uc0ac\uc6a9\ud569\ub2c8\ub2e4.<br>When using the selected database, proceed as follows:<\/p>\n\n\n\n<pre class=\"wp-block-code\" style=\"font-size:14px\"><code>... ...\nexport async function GET() {\n  const db = getDb();\n  await db.init();\n  const users = await db.listUsers();\n  return NextResponse.json(users);\n}\n... ...<\/code><\/pre>\n\n\n\n<p>1)\uc704\uc758 \ucf54\ub4dc\ub294 API\ub85c \ub370\uc774\ud130\ub97c json\ud615\ud0dc\ub85c \ubcf4\uc5ec\uc8fc\ub294 \ubd80\ubd84\uc785\ub2c8\ub2e4<br>The code above displays data in JSON format via an API.<\/p>\n\n\n\n<p>2)\ube0c\ub77c\uc6b0\uc800\uc5d0\uc11c \uc2e4\ud589\uc2dc \uc544\ub798\uc640\uac19\uc774 \uc2e4\ud589\ud558\uba74 \ub429\ub2c8\ub2e4.<br>When running it in a browser, you can do so as shown below.<\/p>\n\n\n\n<pre class=\"wp-block-code\" style=\"font-size:14px\"><code>https:&#47;&#47;localhoste:3000\/api\/users\/\nor\nhttps:\/\/aloy-horizon.duckdns.org\/api\/users\/<\/code><\/pre>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"800\" height=\"800\" src=\"https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2026\/10\/adapter-jpg.jpg\" alt=\"\" class=\"wp-image-13182\" srcset=\"https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2026\/10\/adapter-jpg.jpg 800w, https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2026\/10\/adapter-jpg-300x300.jpg 300w, https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2026\/10\/adapter-jpg-150x150.jpg 150w, https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2026\/10\/adapter-jpg-768x768.jpg 768w, https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2026\/10\/adapter-jpg-400x400.jpg 400w\" sizes=\"auto, (max-width: 800px) 100vw, 800px\" \/><\/figure>\n\n\n\n<p>\ud83d\udcc1 \uc778\ud130\ud398\uc774\uc2a4 \/ Interface<\/p>\n\n\n\n<p>\u2714\ufe0f lib\/db\/adapter.ts <\/p>\n\n\n\n<p>&#8212;  \uc0ac\uc6a9\ub418\ub294 \ud568\uc218\uc774\ub984,\ud615\uc2dd,\ud30c\ub77c\uba54\ud130,\ub9ac\ud134 \ud615\ud0dc,\ud0c0\uc785\ub4f1\uc744 \uc124\uc815\ud569\ub2c8\ub2e4.<br>Define the function names, formats, parameters, return types, and other related specifications.<\/p>\n\n\n\n<pre class=\"wp-block-code\" style=\"font-size:14px\"><code>\/\/ lib\/db\/adapter.ts\n\nexport type User = {\n  id: string;\n  name: string;\n  email: string;\n};\n\nexport type NewUser = User;\n\nexport interface DbAdapter {\n  init(): Promise&lt;void>;\n  close(): Promise&lt;void>;\n  createUser(data: NewUser): Promise&lt;User>;\n  getUserById(id: string): Promise&lt;User | null>;\n  getUserByName(name: string): Promise&lt;User | null>;\n  listUsers(): Promise&lt;User&#91;]>;\n  deleteUser(id: string): Promise&lt;void>;\n}<\/code><\/pre>\n\n\n\n<p>1)lib\/db\/drivers\/sqlite \ub610\ub294 lib\/db\/drivers\/mysql\uc5d0\uc11c  \uc0ac\uc6a9\ub418\ub294 \ud568\uc218\uc758 \uc774\ub984, \ud30c\ub77c\uba54\ud130,\ub9ac\ud134,\ud0c0\uc785\uc744 \uc815\uc758\ud569\ub2c8\ub2e4.<br>Defines the names, parameters, return values, and types of the functions used in <code>lib\/db\/drivers\/sqlite<\/code> or <code>lib\/db\/drivers\/mysql<\/code>.<\/p>\n\n\n\n<p>2)interface\ub97c \ud1b5\ud574\uc11c \uc5b4\ub5a4 \ub370\uc774\ud130\ubca0\uc774\uc2a4\ub97c \uc0ac\uc6a9\ud558\ub358 \ucf54\ub4dc \uc218\uc815 \uc5c6\uc774 \uc0ac\uc6a9\uac00\ub2a5 \ud569\ub2c8\ub2e4.<br>By using an interface, you can work with any database without needing to modify your code.<\/p>\n\n\n\n<p>A.mysql.ts<\/p>\n\n\n\n<pre class=\"wp-block-code\" style=\"font-size:14px\"><code>  async init(): Promise&lt;void> {\n    await this.pool.execute(`\n      CREATE TABLE IF NOT EXISTS \\`user\\` (\n        id VARCHAR(255) PRIMARY KEY,\n        name VARCHAR(255) NOT NULL,\n        email VARCHAR(255) NOT NULL\n      )\n    `);\n  }\n\n  async createUser(data: NewUser): Promise&lt;User> {\n... ...\n    return data;\n  }\n\n  async getUserById(id: string): Promise&lt;User | null> {\n... ...\n    return (rows as User&#91;])&#91;0] || null;\n  }\n\n  async getUserByName(name: string): Promise&lt;User | null> {\n... ...\n    return (rows as User&#91;])&#91;0] || null;\n  }\n\n  async listUsers(): Promise&lt;User&#91;]> {\n... ...\n    return rows as User&#91;];\n  }\n\n  async deleteUser(id: string): Promise&lt;void> {\n... ...\n  }\n\n  async close(): Promise&lt;void> {\n... ...\n  }<\/code><\/pre>\n\n\n\n<p>B.sqlite.ts<\/p>\n\n\n\n<pre class=\"wp-block-code\" style=\"font-size:14px\"><code>... ...\n  async init(): Promise&lt;void> {\n    this.db.exec(`\n      CREATE TABLE IF NOT EXISTS user (\n        id TEXT PRIMARY KEY,\n        name TEXT NOT NULL,\n        email TEXT NOT NULL\n      )\n    `);\n  }\n\n  async createUser(data: NewUser): Promise&lt;User> {\n... ...\n    return data;\n  }\n\n  async getUserById(id: string): Promise&lt;User | null> {\n    return this.db.prepare('SELECT * FROM user WHERE id = ?').get(id) as User || null;\n  }\n\n  async getUserByName(name: string): Promise&lt;User | null> {\n    return this.db.prepare('SELECT * FROM user WHERE name = ?').get(name) as User || null;\n  }\n\n  async listUsers(): Promise&lt;User&#91;]> {\n    return this.db.prepare('SELECT * FROM user').all() as User&#91;];\n  }\n\n  async deleteUser(id: string): Promise&lt;void> {\n    this.db.prepare('DELETE FROM user WHERE id = ?').run(id);\n  }\n\n  async close(): Promise&lt;void> {\n... ...\n  }\n<\/code><\/pre>\n\n\n\n<p>\ud83d\udcc1 \ub77c\uc6b0\ud2b8 \/ route<\/p>\n\n\n\n<p>\u2714\ufe0f \uc2e4\uc81c\ub85c \ud638\ucd9c\ub418\ub294 \ub77c\uc6b0\ud2b8\ub294 \uae00\uc800\uc7a5,\uae00\ubaa9\ub85d,\uc0ad\uc81c \ub77c\uc6b0\ud2b8\uc785\ub2c8\ub2e4.<br>The routes that are actually called are those for saving a post, listing posts, and deleting a post.<\/p>\n\n\n\n<p>&#8212; app\/api\/users\/route.ts -> \uae00\uc800\uc7a5, \uae00\ubaa9\ub85d \/ Save post, Post list<\/p>\n\n\n\n<p>&#8212; app\/api\/users\/[id]\/route.ts -> \uae00 \uc0ad\uc81c \/ Delete post<\/p>\n\n\n\n<p>\u2714\ufe0f \uae00 \uc800\uc7a5 \ubc0f \uae00 \ubaa9\ub85d \/ Save Post and Post List<\/p>\n\n\n\n<pre class=\"wp-block-code\" style=\"font-size:14px\"><code>... ...\n\nexport async function GET() {\n  const db = getDb();\n  await <strong>db.init<\/strong>();\n  const users = await db.listUsers();\n  return NextResponse.json(users);\n}\n\nexport async function POST(req: NextRequest) {\n  const db = getDb();\n  await <strong>db.init<\/strong>();\n  const { id, name, email } = await req.json();\n  \n  const user = await <strong>db.createUser<\/strong>({ id, name, email });\n  return NextResponse.json(user);\n}<\/code><\/pre>\n\n\n\n<p>1)\uad75\uac8c \ud45c\uc2dc\ub41c \uae00\uc790\ub97c mysql.ts\uc640 sqlite.ts\ud30c\uc77c\uc5d0\uc11c \ud568\uc218\ub97c \ubcfc \uc218 \uc788\uc2b5\ub2c8\ub2e4.<br>You can find the functions corresponding to the text in bold within the <code>mysql.ts<\/code> and <code>sqlite.ts<\/code> files.<\/p>\n\n\n\n<p>\u2714\ufe0f \uae00 \uc0ad\uc81c \/ Delete post<\/p>\n\n\n\n<pre class=\"wp-block-code\" style=\"font-size:14px\"><code>... ...\nexport async function DELETE(_: Request, { params }: { params: { id: string } }) {\n  const db = getDb();\n  await <strong>db.init<\/strong>();\n  await <strong>db.deleteUser<\/strong>(params.id);\n  return NextResponse.json({ ok: true });\n}<\/code><\/pre>\n\n\n\n<p>1)\ud568\uc218\uc774\ub984\uacfc \ud30c\ub77c\uba54\ud130\uac00 \ubaa8\ub450 mysql.ts\uc640 sqlite.ts\ud30c\uc77c\uc758 \ub0b4\uc6a9\uacfc \uc77c\uce58\ud558\uace0 adapter.ts\uc5d0\uc11c \uc124\uc815\ud55c \ub0b4\uc6a9\uacfc \ubaa8\ub450 \uc77c\uce58\ud569\ub2c8\ub2e4.<br>The function names and parameters all match the contents of the <code>mysql.ts<\/code> and <code>sqlite.ts<\/code> files, as well as the configurations defined in <code>adapter.ts<\/code>.<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p>\ub9c8\ud0dc\ubcf5\uc74c 21\uc7a5 22\uc808 \/ Matthew 21: 22<\/p>\n\n\n\n<p>&#8220;\ub108\ud76c\uac00 \uae30\ub3c4\ud560 \ub54c\uc5d0 \ubb34\uc5c7\uc774\ub4e0\uc9c0 \ubbff\uace0 \uad6c\ud558\ub294 \uac83\uc740 \ub2e4 \ubc1b\uc73c\ub9ac\ub77c \ud558\uc2dc\ub2c8\ub77c&#8221;<\/p>\n\n\n\n<p>&#8220;And everything you ask in prayer, believing, you will receive.&#8221;<\/p>\n<\/blockquote>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>\ud83d\udc49\ud83c\udffb DB\uc5b4\ub381\ud130 \ubd80\ubd84 \ucd94\uac00 \uc124\uba85\uc785\ub2c8\ub2e4.Here is some additional information regarding the DB adapter component. \ud83d\udcc1 \ud504\ub85c\uc81d\ud2b8 \ub514\ub809\ud1a0\ub9ac \uad6c\uc870 \/ Project Directory Structure \u2714\ufe0f mysql \uc124\uce58 \uc704\uce58 \/ MySQL installation location 1)\uc704\uc758 \uacbd\uc6b0\ub294 \ub9e5OS\uc758 M3\uc778\uacbd\uc6b0 \uc785\ub2c8\ub2e4.The case above applies to the M3 version on macOS. 2)\uc6b4\uc601\uccb4\uc81c\ub9c8\ub2e4 \uc124\uce58 \uacbd\ub85c\uac00 \ub2e4\ub97c \uc218 \uc788\uc2b5\ub2c8\ub2e4.The installation path may vary depending [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":13182,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[28,27,1,7],"tags":[],"class_list":["post-13186","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-news","category-nextjs","category-uncategorized","category-website","has-thumbnail"],"_links":{"self":[{"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/posts\/13186","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=13186"}],"version-history":[{"count":53,"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/posts\/13186\/revisions"}],"predecessor-version":[{"id":13241,"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/posts\/13186\/revisions\/13241"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/media\/13182"}],"wp:attachment":[{"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/media?parent=13186"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/categories?post=13186"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/tags?post=13186"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}