Sooyoung Archive
캠핑인스타 만들기 첫편
캠핑인스타 (1) - Next.js와 한국관광공사 API로 캠핑 로그 서비스 만들기
🏕️ 프로젝트 소개
안녕하세요! 오늘은 Next.js와 한국관광공사 API, 그리고 카카오 소셜 로그인을 연동한 캠핑 로그 서비스 "캠핑인스타" 개발 과정을 공유해드리려고 합니다.
✨ 주요 기능
- 카카오 소셜 로그인 - 3초 만에 간편 로그인
- 한국관광공사 API 연동 - 전국 캠핑장 정보 조회
- 캠핑장 검색 및 저장 - 마음에 드는 캠핑장 저장하기
- 피드 시스템 - 다른 사람들의 캠핑 후기 구경하기
🛠️ 기술 스택
프론트엔드
- Next.js 16 - 풀스택 리액트 프레임워크
- TypeScript - 타입 안전성 확보
- Tailwind CSS - 모던한 스타일링
- Shadcn/ui - 아름다운 UI 컴포넌트 라이브러리
백엔드 & 데이터
- Supabase - 데이터베이스 및 인증 서비스
- 한국관광공사 GoCamping API - 캠핑장 데이터 제공
인증
- 카카오 OAuth 2.0 - 소셜 로그인 연동
🔥 개발 과정
1단계: 프로젝트 셋업
먼저 Next.js 프로젝트를 생성하고 필요한 라이브러리들을 설치했습니다.
npx create-next-app@latest my-camp-log --typescript --tailwind --app
cd my-camp-log
npm install @supabase/supabase-js @supabase/ssr
npm install @radix-ui/react-*
npm install lucide-react
2단계: 한국관광공사 API 연동
가장 먼저 한 것은 한국관광공사의 GoCamping API 연동이었습니다.
API 키 발급
- 공공데이터포털에서 회원가입
- "고캠핑" API 검색 후 활용신청
- API 키 발급 (승인까지 1~2일 소요)
API 연동 코드
// src/lib/actions/camping.ts
const API_BASE_URL = "http://apis.data.go.kr/B551011/GoCamping";
export async function fetchCampingList(keyword: string): Promise<CampingItem[]> {
const apiKey = process.env.GO_CAMPING_API_KEY;
if (!apiKey) {
console.error("GO_CAMPING_API_KEY is not configured");
return [];
}
const params = new URLSearchParams({
serviceKey: apiKey,
numOfRows: "10",
pageNo: "1",
MobileOS: "ETC",
MobileApp: "MyCampLog",
_type: "json",
...(keyword.trim() && { keyword: keyword.trim() }),
});
const url = `${API_BASE_URL}/searchList?${params.toString()}`;
const res = await fetch(url, { next: { revalidate: 3600 } });
const data = await res.json();
return parseApiItems(data);
}
타입 정의
// src/types/camping.ts
export interface CampingItem {
contentId?: string;
facltNm: string; // 캠핑장 이름
lineIntro?: string; // 한줄소개
addr1: string; // 주소
firstImageUrl?: string; // 대표이미지
tel?: string; // 전화번호
homepage?: string; // 홈페이지
induty?: string; // 업종
mapX?: string; // 경도
mapY?: string; // 위도
}
3단계: 카카오 소셜 로그인 구현
Supabase를 활용해 카카오 OAuth 로그인을 구현했습니다.
Supabase 설정
- Supabase 프로젝트 생성
- Authentication > Settings에서 Kakao 활성화
- 카카오 디벨로퍼스에서 REST API 키 발급
- Supabase에 Kakao Client ID와 Secret 입력
카카오 로그인 컴포넌트
// src/components/auth/kakao-button.tsx
export function KakaoButton() {
const [isLoading, setIsLoading] = useState(false);
const supabase = createClient();
const handleKakaoLogin = async () => {
setIsLoading(true);
try {
const { error } = await supabase.auth.signInWithOAuth({
provider: "kakao",
options: {
redirectTo: `${window.location.origin}/auth/callback`,
queryParams: {
scope: "profile_nickname, profile_image, account_email",
},
},
});
} catch (err) {
console.error("Kakao login error:", err);
}
};
return (
<button
onClick={handleKakaoLogin}
className="w-full h-12 rounded-lg font-semibold text-[#191919] bg-[#FEE500] hover:bg-[#FDD835]"
>
<span>카카오로 3초 만에 시작하기</span>
</button>
);
}
OAuth 콜백 처리
// src/app/auth/callback/route.ts
export async function GET(request: Request) {
const requestUrl = new URL(request.url);
const code = requestUrl.searchParams.get("code");
const next = requestUrl.searchParams.get("next") || "/dashboard";
if (code) {
const supabase = await createClient();
const { error } = await supabase.auth.exchangeCodeForSession(code);
if (!error) {
return NextResponse.redirect(new URL(next, request.url));
}
}
return NextResponse.redirect(new URL("/login?error=auth-code-error", request.url));
}
4단계: 데이터베이스 스키마 설계
캠핑장 저장과 피드 기능을 위한 테이블을 설계했습니다.
-- saved_campsites 테이블
CREATE TABLE saved_campsites (
id UUID DEFAULT gen_random_uuid() PRIMARY KEY,
user_id UUID REFERENCES auth.users(id),
camp_id VARCHAR(255) NOT NULL,
camp_name VARCHAR(255) NOT NULL,
address TEXT,
content TEXT,
image_url TEXT,
is_public BOOLEAN DEFAULT false,
visited_date DATE,
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW()
);
🎨 UI/UX 구현
메인 페이지
- 캠핑장 검색 기능
- 카드 형태의 캠핑장 목록
- 반응형 디자인
대시보드
- 저장한 캠핑장 목록
- 피드 기능 (다른 사람들의 후기)
- 마이페이지
캠핑장 상세 페이지
- 상세 정보 표시
- 저장하기 기능
- 후기 작성
🚀 핵심 기능 구현 팁
1. API 데이터 캐싱
// Next.js의 캐싱 활용
const res = await fetch(url, {
next: { revalidate: 3600 } // 1시간 캐싱
});
2. 에러 핸들링
try {
const data = await fetchCampingList(keyword);
setCampingSites(data);
} catch (error) {
toast.error("캠핑장 정보를 불러오는데 실패했습니다.");
}
3. 로딩 상태 관리
const [isLoading, setIsLoading] = useState(false);
const handleSearch = async () => {
setIsLoading(true);
try {
const results = await fetchCampingList(keyword);
setCampingSites(results);
} finally {
setIsLoading(false);
}
};
📱 배포 및 운영
환경 변수 설정
# .env.local
NEXT_PUBLIC_SUPABASE_URL=your_supabase_url
NEXT_PUBLIC_SUPABASE_ANON_KEY=your_supabase_anon_key
GO_CAMPING_API_KEY=your_go_camping_api_key
Vercel 배포
npm run build
vercel --prod
🎯 다음 포스팅 예정
다음 포스팅에서는 다음 기능들을 구현하는 과정을 다룰 예정입니다:
- 지도 기능 - 카카오맵 연동으로 캠핑장 위치 표시
- 이미지 업로드 - 캠핑 사진 업로드 및 갤러리
- 예약 기능 - 캠핑장 예약 연동
- 실시간 채팅 - 캠퍼들과의 소통 기능
💬 마무리
오늘은 Next.js와 한국관광공사 API, 카카오 로그인을 연동한 캠핑 로그 서비스의 기본 골격을 만들어봤습니다.
외부 API 연동과 소셜 로그인 구현은 처음에는 복잡해 보이지만, 한번 설정해두면 다른 프로젝트에서도 재사용할 수 있는 귀중한 경험이 됩니다.
궁금한 점이 있다면 댓글로 남겨주세요! 👨💻
#NextJS #캠핑 #한국관광공사API #카카오로그인 #Supabase #개발일지