-
[ Next ] 공휴일 Open Api 만들기Front/Next 2026. 3. 12. 18:57반응형
만드는 프로젝트에 캘린더가 들어가면 항상 공공데이터포털에서 api를 호출해서 사용해야하기 때문에
이전 라이브러리는 직접 공공데이터포털 api를 호출해서 뿌려주기때문에 결국에는 직접 공휴일이나 날짜를 자유롭게 설정할 수 없기때문에
직접 관리자 페이지에서 공용으로 사용할 수 있는 open API를 만들어서 사용하기로 했다.
공공데이터포털
https://www.data.go.kr/data/15012690/openapi.do
우선 공공데이터포털 특일정보 api 활용신청 후 인증키를 발급
공휴일 Api 만들기
공공데이터포털은 파라미터가 년도와 월을 보내야하므로
년도를 보내면 1월부터 12월까지 반복문을 돌려 해당 년도의 모든 공휴일을 가져와서 저장
1월 1일은 신정이 아닌 1월1일로 나오고 크리스마스는 기독탄신일로 나와서 신정과 성탄절로 이름을 바꿔서 db에 저장할 수 있도록 바꿔준다.export interface Holidays { year: number, holidays: Record<string, string> } const holidayNameMap: Record<string, string> = { "1월1일": "신정", "기독탄신일": "성탄절", }; export const runScheduler = async (year: number) => { const holidayMap: Record<string, string> = {}; for (let month = 1; month <= 12; month++) { const solMonth = String(month).padStart(2, "0"); const items = await getHolidays(year, solMonth); items.forEach((h: any) => { const name = holidayNameMap[h.dateName] ?? h.dateName; holidayMap[h.locdate] = name; }); } return holidayMap }; async function getHolidays(year: number, month: string) { const SERVICE_KEY = process.env.NEXT_PUBLIC_HOLIDAY_SERVICE_KEY; const url = `https://apis.data.go.kr/B090041/openapi/service/SpcdeInfoService/getRestDeInfo?serviceKey=${SERVICE_KEY}&solYear=${year}&solMonth=${month}&_type=json`; const res = await fetch(url, { cache: 'no-store' }); if (!res.ok) throw new Error('Failed to fetch holidays'); const data = await res.json(); const items = data.response.body.items; if (!items || items === "") return []; const holidayItem = items.item; return Array.isArray(holidayItem) ? holidayItem : [holidayItem]; }이후 지속적으로 업데이트를 해주기 위해서
스케쥴러를 사용
vercel.json을 루트 프로젝트에 만든다.
스케쥴러를 돌릴 api 경로를 넣고 스케쥴 기간을 설정한다.
{ "crons": [ { "path": "api/scheduler", "schedule": "0 0 1 */4 *" } ] }이제 mongoDB를 사용하고있어 db 저장 로직을 만든다.
수동으로 데이터를 요청하고 저장할 수 있도록 파라미터에 년도가 있을때는 해당 년도로 없을때는 올해로 호출할 수 있게 한다.
이후 기존에 데이터가 있으면 update 없으면 insert를 한다.
import { runScheduler } from "@/lib/holiday"; import clientPromise from "@/lib/mongodb"; export async function POST(request: Request) { let requestYear = new Date().getFullYear(); const {year} = await request.json(); if(year) { requestYear = Number(year); } const holidayMap = await runScheduler(requestYear); const client = await clientPromise const db = client.db("OpenApi") try { const collection = db.collection("holidays") await collection.updateOne( { year: requestYear }, { $set: { year: requestYear, holidays: holidayMap, updatedAt: new Date(), }, }, { upsert: true } ); } catch (e) { console.log(e); } return Response.json({ status: 200, data: holidayMap, message: "scheduler executed" }); }
공휴일 조회 Api
이제 조회 api를 만들어서 실제로 사용한다.
이때 조회할때는 db과부하를 방지하여 redis를 활용해 캐싱하여 최적화 진행
redis는 upstash라이브러리를 사용하여 개발
https://yumedev.tistory.com/85
[ Next ] Redis 사용하여 캐시 관리
네이버랑 카카오 api를 활용하여 데이터를 가져오는 프로젝트를 하고 있는데이 경우에 계속 api를 호출하면 횟수가 금방 줄어들기때문에 이를redis를 활용하여 캐시 관리하여 횟수를 줄이고자 했
yumedev.tistory.com
조회 api를 만들고 redis 캐싱 처리 key는 년도로 처리하고 동시에 해당 년도가 없을경우 db에 저장하도록 한다.
import clientPromise from "@/lib/mongodb"; import {Holidays, runScheduler} from "@/lib/holiday"; import {redis} from "@/lib/redis"; export async function POST(request: Request) { const { year } = await request.json(); const client = await clientPromise; const db = client.db("OpenApi"); const key = `open:holidays:${year}` const cached: string | null = await redis.get(key) if (cached != null) { return Response.json({status: 200, data: cached, cached: true}) } try { const collection = db.collection<Holidays>("holidays"); const response = await collection.findOne({ year }); if(!response) { const holidayMap = await runScheduler(year) await redis.set(key,JSON.stringify(holidayMap),{ex: 86400}) return Response.json({ status: 200, data: holidayMap, }); } const holidays = response?.holidays ?? {}; await redis.set(key,JSON.stringify(holidays),{ex: 86400}) return Response.json({ status: 200, data: holidays, }); } catch (e) { return Response.json({ status: 400, data: null, message: "공휴일 데이터 조회 오류", }); } }
공휴일 Api 사용
이제 만든 api를 vercel로 배포 후 사용
api호출하는 함수를 만든다.
export const getHolidays = async (year: number) => { try { const response = await fetch(BASE_API_URL + HOLIDAYS_URL, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ year }), }); const result = await response.json(); if (result.status === 200) { return result.data; } else { throw new Error(result.message || '데이터 조회 실패'); } } catch (error) { console.error('Holiday Fetch Error:', error); throw error; } }https://yumedev.tistory.com/102
[ React Native ] 캘린더 공휴일 데이터 API
공휴일 데이터를 관리자 페이지에서 공공데이터포털 api를 활용헤서 저장후이걸 가져와서 처리할까 고민했지만무료로 사용할 수 있는 것이 있어서 해당 라이브러리를 사용하기로했다. git에 해
yumedev.tistory.com
이제 native프로젝트에 기존에 만들었던 로직을 직접 만든 api로 바꿔준다.
기존 로직을 내 api에 맞게 수정
import {create} from "zustand/react"; import {holidays} from '@kyungseopk1m/holidays-kr'; interface AppState { //... // 휴일 정보 캐싱 holidayMap: Record<string, string> loadHolidays: (year: number) => Promise<void> } export const useAppStore = create<AppState>((set,get) => ({ //... holidayMap: {}, loadHolidays: async (year) => { const holidays = await getHolidays(year) console.log(holidays) set((state) => ({ holidayMap: { ...state.holidayMap, [year]: holidays, }, })) }, }))그럼 이제 데이터가 정상적으로 불러온것을 볼 수 있다.
728x90반응형'Front > Next' 카테고리의 다른 글
[ Next ] Alert, Confirm 커스텀 Hook (0) 2025.12.05 [ Next ] KaKao 지도 API 사용하기 (0) 2025.09.28 [ Next ] Redis 사용하여 캐시 관리 (0) 2025.09.28 [ Next ] MongoDB 연결 (0) 2025.09.27 [ Next ] Ably Realtime 무료 소켓 활용하여 채팅 만들기 (0) 2025.09.27