Next.js 풀스택 앱 만들기
Next.js 풀스택 앱 만들기 — Next.js App Router에서 서버·클라이언트 양쪽으로 ConnectBase를 활용합니다
Next.js App Router에서 서버·클라이언트 양쪽으로 ConnectBase를 활용합니다
이 튜토리얼에서 배울 내용
Next.js 풀스택 앱 만들기
Next.js의 강점은 서버와 클라이언트를 하나의 프로젝트에서 모두 다룰 수 있다는 것입니다. ConnectBase와 함께 사용하면 서버에서는 Secret Key로 안전하게, 클라이언트에서는 Public Key로 빠르게 데이터에 접근할 수 있습니다.
이 가이드에서는 App Router 기반으로 Server Components, Server Actions, API Routes를 모두 활용하는 방법을 다룹니다.
📌 이 가이드는 Next.js App Router에 대한 기본 지식이 있다고 가정합니다.
1. 설치
npm install connectbase-client2. 환경 변수 설정
Next.js에서는 환경 변수 이름에 따라 서버/클라이언트 접근이 결정됩니다:
NEXT_PUBLIC_으로 시작하면 → 클라이언트에서도 접근 가능 (Public Key용)- 그 외 → 서버에서만 접근 가능 (Secret Key용)
.env.local:
NEXT_PUBLIC_CONNECT_BASE_PUBLIC_KEY=cb_pk_...
CONNECT_BASE_SECRET_KEY=cb_sk_... # 서버 사이드용3. SDK 인스턴스 분리하기
ConnectBase SDK 인스턴스를 클라이언트용과 서버용 두 개로 나눕니다. 서버용은 Secret Key를 사용하므로 더 많은 권한을 가집니다 (데이터 삭제, 관리자 기능 등).
lib/connectbase.ts:
import ConnectBase from 'connectbase-client'
// 클라이언트 사이드
export const cb = new ConnectBase({
publicKey: process.env.NEXT_PUBLIC_CONNECT_BASE_PUBLIC_KEY!
})
// 서버 사이드 (API Routes, Server Components)
export const cbServer = new ConnectBase({
secretKey: process.env.CONNECT_BASE_SECRET_KEY!
})4. Server Components에서 데이터 조회하기
Server Components는 서버에서 실행되므로 Secret Key를 안전하게 사용할 수 있습니다.
async/await로 직접 데이터를 가져와 HTML로 렌더링합니다 — API 라우트를 별도로 만들 필요가 없습니다.
app/users/page.tsx:
import { cbServer } from '@/lib/connectbase'
const USERS_TABLE_ID = process.env.USERS_TABLE_ID!
interface UserRow { id: string; data: { name: string; email?: string } }
async function getUsers(): Promise<UserRow[]> {
const response = await cbServer.database.queryData(USERS_TABLE_ID, {
orderBy: [{ field: 'createdAt', direction: 'desc' }],
limit: 20,
})
return response.data as UserRow[]
}
export default async function UsersPage() {
const users = await getUsers()
return (
<div>
<h1>사용자 목록</h1>
<ul>
{users.map(user => (
<li key={user.id}>{user.data.name}</li>
))}
</ul>
</div>
)
}5. Server Actions으로 데이터 생성/수정하기
Server Actions는 클라이언트의 폼 제출을 서버에서 처리하는 기능입니다.
'use server' 지시어를 사용하면 함수가 서버에서 실행되므로, Secret Key를 안전하게 사용할 수 있습니다.
app/actions.ts:
'use server'
import { cbServer } from '@/lib/connectbase'
import { revalidatePath } from 'next/cache'
const USERS_TABLE_ID = process.env.USERS_TABLE_ID!
export async function createUser(formData: FormData) {
const name = formData.get('name') as string
const email = formData.get('email') as string
await cbServer.database.createData(USERS_TABLE_ID, {
data: { name, email },
})
revalidatePath('/users')
}
export async function deleteUser(userId: string) {
await cbServer.database.deleteData(USERS_TABLE_ID, userId)
revalidatePath('/users')
}6. API Routes — 외부 웹훅 처리
외부 서비스(결제 완료 알림, GitHub 이벤트 등)에서 보내는 웹훅을 처리하는 API 엔드포인트를 만듭니다. 서명 검증으로 요청의 진위를 확인하는 것이 중요합니다.
app/api/webhook/route.ts:
import { NextRequest, NextResponse } from 'next/server'
import { cbServer } from '@/lib/connectbase'
import crypto from 'crypto'
export async function POST(request: NextRequest) {
const body = await request.json()
const signature = request.headers.get('x-connectbase-signature')
// 서명 검증
const expectedSignature = crypto
.createHmac('sha256', process.env.WEBHOOK_SECRET!)
.update(JSON.stringify(body))
.digest('hex')
if (signature !== expectedSignature) {
return NextResponse.json({ error: 'Invalid signature' }, { status: 401 })
}
// 이벤트 처리
console.log('Webhook event:', body.type)
return NextResponse.json({ success: true })
}7. 클라이언트 컴포넌트에서 Server Actions 호출하기
'use client' 컴포넌트에서 Server Actions를 호출하는 방법입니다.
폼을 제출하면 Server Action이 서버에서 실행되어 데이터를 저장합니다.
components/CreateUserForm.tsx:
'use client'
import { useState } from 'react'
import { createUser } from '@/app/actions'
export function CreateUserForm() {
const [pending, setPending] = useState(false)
async function handleSubmit(formData: FormData) {
setPending(true)
await createUser(formData)
setPending(false)
}
return (
<form action={handleSubmit}>
<input name="name" placeholder="이름" required />
<input name="email" type="email" placeholder="이메일" required />
<button disabled={pending}>
{pending ? '생성 중...' : '사용자 생성'}
</button>
</form>
)
}이 튜토리얼이 도움이 됐나요?