From 32329b1cb7d43ec8f3a8d27ba50038123f9ec39a Mon Sep 17 00:00:00 2001 From: Daseul Kim Date: Mon, 9 Jun 2025 17:47:15 +0900 Subject: [PATCH] =?UTF-8?q?docs:=20=EC=A7=80=EB=B6=95=EC=9E=AC=EC=A0=81?= =?UTF-8?q?=ED=95=A9=EC=84=B1=20api=20description=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/api/suitable/list/route.ts | 53 ++++++++++++++++++++++++++---- src/app/api/suitable/pdf/route.ts | 41 +++++++++++++++++++---- src/app/api/suitable/pick/route.ts | 32 ++++++++++++++++-- src/app/api/suitable/route.ts | 45 +++++++++++++++++++++++-- 4 files changed, 151 insertions(+), 20 deletions(-) diff --git a/src/app/api/suitable/list/route.ts b/src/app/api/suitable/list/route.ts index 6f9260c..c668153 100644 --- a/src/app/api/suitable/list/route.ts +++ b/src/app/api/suitable/list/route.ts @@ -2,19 +2,58 @@ import { NextRequest, NextResponse } from 'next/server' import { prisma } from '@/libs/prisma' import { type Suitable } from '@/types/Suitable' +/** + * @api {get} /api/suitable/list 지붕재 적합성 데이터 조회 API + * @apiName GetSuitableList + * @apiGroup Suitable + * + * @apiDescription + * 지붕재 적합성 데이터의 일부 컬럼을 조회 + * + * @apiParam {Number} pageNumber 페이지 번호 + * @apiParam {Number} itemPerPage 페이지당 아이템 수 + * @apiParam {String} [category] 지붕재그룹코드 (예: RMG001) + * @apiParam {String} [keyword] 검색키워드 + * + * @apiExample {curl} Example usage: + * curl -X GET \ + * -G "pageNumber=1" \ + * -G "itemPerPage=10" \ + * -G "category=RMG001" \ + * -G "keyword=검색키워드" \ + * http://localhost:3000/api/suitable/list + * + * @apiSuccess {Array} suitable 지붕재 적합성 데이터 + * @apiSuccessExample {json} Success-Response: + * [ + * { + * "id": 1, + * "product_name": "test", + * "detail_cnt": 1, + * "detail": [ + * { + * "id": 1, + * "trestle_mfpc_cd": "test", + * "trestle_manufacturer_product_name": "test", + * "memo": "test" + * } + * ] + * } + * ] + */ export async function GET(request: NextRequest) { try { const searchParams = request.nextUrl.searchParams - const pageNumber = parseInt(searchParams.get('pageNumber') || '0') const itemPerPage = parseInt(searchParams.get('itemPerPage') || '0') + const category = searchParams.get('category') + const keyword = searchParams.get('keyword') + + /* 파라미터 체크 */ if (pageNumber === 0 || itemPerPage === 0) { return NextResponse.json({ error: '페이지 번호와 페이지당 아이템 수가 필요합니다' }, { status: 400 }) } - const category = searchParams.get('category') - const keyword = searchParams.get('keyword') - let query = ` SELECT msm.id @@ -48,7 +87,7 @@ export async function GET(request: NextRequest) { FETCH NEXT @P2 ROWS ONLY; ` - // 검색 조건 설정 + /* 검색 조건 설정 */ if (category) { const roofMtQuery = ` SELECT roof_mt_cd @@ -71,7 +110,7 @@ export async function GET(request: NextRequest) { }, }) } catch (error) { - console.error('❌ 데이터 조회 중 오류가 발생했습니다:', error) - return NextResponse.json({ error: '데이터 조회 중 오류가 발생했습니다' }, { status: 500 }) + console.error(`데이터 조회 중 오류가 발생했습니다: ${error}`) + return NextResponse.json({ error: `데이터 조회 중 오류가 발생했습니다: ${error}` }, { status: 500 }) } } diff --git a/src/app/api/suitable/pdf/route.ts b/src/app/api/suitable/pdf/route.ts index 1525cfb..768f81e 100644 --- a/src/app/api/suitable/pdf/route.ts +++ b/src/app/api/suitable/pdf/route.ts @@ -6,13 +6,35 @@ import { prisma } from '@/libs/prisma' import { type Suitable } from '@/types/Suitable' import SuitablePdf from '@/components/pdf/SuitablePdf' +/** + * @api {post} /api/suitable/pdf 지붕재 적합성 PDF 다운로드 API + * @apiName CreateSuitablePdf + * @apiGroup Suitable + * + * @apiDescription + * 지붕재 적합성 데이터를 PDF 파일로 다운로드 + * + * @apiBody {FormData} form-data + * @apiBody {String} form-data.ids 메인 ID 목록 (쉼표로 구분된 문자열) + * @apiBody {String} form-data.detailIds 상세 ID 목록 (쉼표로 구분된 문자열) + * @apiBody {String} form-data.fileTitle PDF 파일 제목 + * + * @apiExample {curl} Example usage: + * curl -X POST \ + * -F "ids=1,2,3" \ + * -F "detailIds=4,5,6" \ + * -F "fileTitle=적합성조사보고서" \ + * http://localhost:3000/api/suitable/pdf + * + * @apiSuccess {File} 지붕재 적합성 PDF 파일 + */ export async function POST(request: NextRequest) { - // 파라미터 체크 const formData = await request.formData() const ids = formData.get('ids') as string const detailIds = formData.get('detailIds') as string const fileTitle = formData.get('fileTitle') as string + /* 파라미터 체크 */ if (ids === '' || detailIds === '' || fileTitle === '') { return NextResponse.json({ error: '필수 파라미터가 누락되었습니다' }, { status: 400 }) } @@ -59,14 +81,14 @@ export async function POST(request: NextRequest) { ORDER BY msm.product_name; ` - // 검색 조건 설정 + /* 검색 조건 설정 */ query = query.replaceAll(':mainIds', ids) query = query.replaceAll(':detailIds', detailIds) - // 데이터 조회 + /* 데이터 조회 */ const suitable: Suitable[] = await prisma.$queryRawUnsafe(query) - // pdf 생성 : mainId 100개씩 청크로 나누기 + /* pdf 생성 : mainId 100개씩 청크로 나누기 */ const CHUNK_SIZE = 100 const pdfBuffers: Uint8Array[] = [] for (let i = 0; i < suitable.length; i += CHUNK_SIZE) { @@ -85,7 +107,7 @@ export async function POST(request: NextRequest) { pdfBuffers.push(new Uint8Array(arrayBuffer)) } - // 모든 PDF 버퍼 병합 + /* 모든 PDF 버퍼 병합 */ const mergedPdfBytes = await mergePdfBuffers(pdfBuffers) const fileName = `${fileTitle.replace(' ', '_')}.pdf` @@ -98,11 +120,16 @@ export async function POST(request: NextRequest) { }, }) } catch (error) { - console.error('❌ 데이터 조회 중 오류가 발생했습니다:', error) - return NextResponse.json({ error: '데이터 조회 중 오류가 발생했습니다' }, { status: 500 }) + console.error(`데이터 조회 중 오류가 발생했습니다: ${error}`) + return NextResponse.json({ error: `데이터 조회 중 오류가 발생했습니다: ${error}` }, { status: 500 }) } } +/** + * @description PDF 버퍼 병합 + * @param buffers 병합할 PDF 버퍼 + * @returns 병합된 PDF 버퍼 + */ async function mergePdfBuffers(buffers: Uint8Array[]) { const mergedPdf = await PDFDocument.create() diff --git a/src/app/api/suitable/pick/route.ts b/src/app/api/suitable/pick/route.ts index 922a1d3..2865777 100644 --- a/src/app/api/suitable/pick/route.ts +++ b/src/app/api/suitable/pick/route.ts @@ -1,6 +1,32 @@ import { NextRequest, NextResponse } from 'next/server' import { prisma } from '@/libs/prisma' +/** + * @api {get} /api/suitable/pick 지붕재 적합성 데이터 아이디 조회 API + * @apiName GetSuitablePick + * @apiGroup Suitable + * + * @apiDescription + * 지붕재 적합성 데이터의 검색 조건에 맞는 main_id와 detail_id를 조회 + * + * @apiParam {String} [category] 지붕재그룹코드 (예: RMG001) + * @apiParam {String} [keyword] 검색키워드 + * + * @apiExample {curl} Example usage: + * curl -X GET \ + * -G "category=RMG001" \ + * -G "keyword=검색키워드" \ + * http://localhost:3000/api/suitable/pick + * + * @apiSuccess {Array} suitableIdSet 지붕재 적합성 데이터의 아이디 목록 + * @apiSuccessExample {json} Success-Response: + * [ + * { + * "id": 1, + * "detail_id": "1,2,3" + * } + * ] + */ export async function GET(request: NextRequest) { try { const searchParams = request.nextUrl.searchParams @@ -26,7 +52,7 @@ export async function GET(request: NextRequest) { ; ` - // 검색 조건 설정 + /* 검색 조건 설정 */ if (category) { const roofMtQuery = ` SELECT roof_mt_cd @@ -45,7 +71,7 @@ export async function GET(request: NextRequest) { return NextResponse.json(suitableIdSet) } catch (error) { - console.error('❌ 데이터 조회 중 오류가 발생했습니다:', error) - return NextResponse.json({ error: '데이터 조회 중 오류가 발생했습니다' }, { status: 500 }) + console.error(`데이터 조회 중 오류가 발생했습니다: ${error}`) + return NextResponse.json({ error: `데이터 조회 중 오류가 발생했습니다: ${error}` }, { status: 500 }) } } diff --git a/src/app/api/suitable/route.ts b/src/app/api/suitable/route.ts index 173b6ea..888e663 100644 --- a/src/app/api/suitable/route.ts +++ b/src/app/api/suitable/route.ts @@ -2,12 +2,51 @@ import { NextRequest, NextResponse } from 'next/server' import { prisma } from '@/libs/prisma' import { Suitable } from '@/types/Suitable' +/** + * @api {post} /api/suitable 지붕재 적합성 데이터 모든 컬럼 조회 API + * @apiName GetSuitable + * @apiGroup Suitable + * + * @apiDescription + * 지붕재 적합성 데이터의 모든 컬럼을 조회 + * + * @apiBody {FormData} form-data + * @apiBody {String} form-data.ids 메인 ID 목록 (쉼표로 구분된 문자열) + * @apiBody {String} form-data.detailIds 상세 ID 목록 (쉼표로 구분된 문자열) + * + * @apiExample {curl} Example usage: + * curl -X POST \ + * -F "ids=1,2,3" \ + * -F "detailIds=4,5,6" \ + * http://localhost:3000/api/suitable + * + * @apiSuccess {Array} suitable 지붕재 적합성 데이터 + * @apiSuccessExample {json} Success-Response: + * [ + * { + * "id": 1, + * "product_name": "test", + * "manu_ft_cd": "test", + * "roof_mt_cd": "test", + * "roof_sh_cd": "test", + * "detail": [ + * { + * "id": 1, + * "trestle_mfpc_cd": "MFPC001", + * "trestle_manufacturer_product_name": "test", + * "memo": "test" + * } + * ] + * } + * ] + */ export async function POST(request: NextRequest) { try { const body: Record = await request.json() const ids = body.ids const detailIds = body.detailIds + /* 파라미터 체크 */ if (ids === '' || detailIds === '') { return NextResponse.json({ error: '필수 파라미터가 누락되었습니다' }, { status: 400 }) } @@ -45,7 +84,7 @@ export async function POST(request: NextRequest) { ORDER BY msm.product_name; ` - // 검색 조건 설정 + /* 검색 조건 설정 */ query = query.replaceAll(':mainIds', ids) query = query.replaceAll(':detailIds', detailIds) @@ -53,7 +92,7 @@ export async function POST(request: NextRequest) { return NextResponse.json(suitable) } catch (error) { - console.error('❌ 데이터 조회 중 오류가 발생했습니다:', error) - return NextResponse.json({ error: '데이터 조회 중 오류가 발생했습니다' }, { status: 500 }) + console.error(`데이터 조회 중 오류가 발생했습니다: ${error}`) + return NextResponse.json({ error: `데이터 조회 중 오류가 발생했습니다: ${error}` }, { status: 500 }) } }