diff options
Diffstat (limited to 'app/api')
| -rw-r--r-- | app/api/table/items/infinite/route.ts | 232 |
1 files changed, 232 insertions, 0 deletions
diff --git a/app/api/table/items/infinite/route.ts b/app/api/table/items/infinite/route.ts new file mode 100644 index 00000000..486c3076 --- /dev/null +++ b/app/api/table/items/infinite/route.ts @@ -0,0 +1,232 @@ +// app/api/table/items/infinite/route.ts +import { NextRequest, NextResponse } from "next/server"; +import { getItemsInfinite, type GetItemsInfiniteInput } from "@/lib/items/service"; + +// URL 파라미터를 GetItemsInfiniteInput으로 변환하는 헬퍼 함수 +function parseUrlParamsToInfiniteInput(searchParams: URLSearchParams): GetItemsInfiniteInput { + // 무한 스크롤 관련 파라미터 + const cursor = searchParams.get("cursor") || undefined; + const limit = parseInt(searchParams.get("limit") || "50"); + + // 기존 searchParamsCache와 동일한 필드들 + const itemCode = searchParams.get("itemCode") || ""; + const itemName = searchParams.get("itemName") || ""; + const description = searchParams.get("description") || ""; + const parentItemCode = searchParams.get("parentItemCode") || ""; + const itemLevel = parseInt(searchParams.get("itemLevel") || "5"); + const deleteFlag = searchParams.get("deleteFlag") || ""; + const unitOfMeasure = searchParams.get("unitOfMeasure") || ""; + const steelType = searchParams.get("steelType") || ""; + const gradeMaterial = searchParams.get("gradeMaterial") || ""; + const changeDate = searchParams.get("changeDate") || ""; + const baseUnitOfMeasure = searchParams.get("baseUnitOfMeasure") || ""; + + // 고급 필터링 관련 + const search = searchParams.get("search") || ""; + const joinOperator = searchParams.get("joinOperator") || "and"; + + // 필터 파라미터 파싱 + let filters: any[] = []; + const filtersParam = searchParams.get("filters"); + if (filtersParam) { + try { + filters = JSON.parse(filtersParam); + } catch (e) { + console.warn("Invalid filters parameter:", e); + filters = []; + } + } + + // 정렬 파라미터 파싱 + let sort: Array<{ id: string; desc: boolean }> = []; + const sortParam = searchParams.get("sort"); + if (sortParam) { + try { + sort = JSON.parse(sortParam); + } catch (e) { + console.warn("Invalid sort parameter:", e); + // 기본 정렬 + sort = [{ id: "createdAt", desc: true }]; + } + } else { + // 정렬이 없으면 기본 정렬 + sort = [{ id: "createdAt", desc: true }]; + } + + // 플래그 파라미터 파싱 + let flags: string[] = []; + const flagsParam = searchParams.get("flags"); + if (flagsParam) { + try { + flags = JSON.parse(flagsParam); + } catch (e) { + console.warn("Invalid flags parameter:", e); + flags = []; + } + } + + // searchParamsCache의 모든 필드를 포함한 입력 객체 생성 + return { + // 무한 스크롤 관련 + cursor, + limit, + + // 기본 필터 필드들 (searchParamsCache와 동일) + itemCode, + itemName, + description, + parentItemCode, + itemLevel, + deleteFlag, + unitOfMeasure, + steelType, + gradeMaterial, + changeDate, + baseUnitOfMeasure, + + // 고급 필터링 + search, + filters, + joinOperator: joinOperator as "and" | "or", + + // 정렬 + sort, + + // 플래그 + flags, + }; +} + +export async function GET(request: NextRequest) { + try { + const searchParams = request.nextUrl.searchParams; + + console.log('API Request URL:', request.url); + console.log('Search Params:', Object.fromEntries(searchParams.entries())); + + // URL 파라미터를 서비스 입력으로 변환 + const input = parseUrlParamsToInfiniteInput(searchParams); + + console.log('Parsed Input:', JSON.stringify(input, null, 2)); + + // 무한 스크롤 서비스 함수 호출 + const result = await getItemsInfinite(input); + + console.log('Service Result:', { + dataCount: result.data.length, + hasNextPage: result.hasNextPage, + nextCursor: result.nextCursor, + total: result.total, + }); + + // 응답에 메타데이터 추가 + const response = { + mode: 'infinite' as const, + ...result, + meta: { + table: 'items', + displayName: 'Package Items', + requestedLimit: input.limit || 50, + actualLimit: Math.min(input.limit || 50, 100), + maxPageSize: 100, + cursor: input.cursor || null, + apiVersion: '1.0', + timestamp: new Date().toISOString(), + supportedFields: [ + 'itemCode', 'itemName', 'description', 'parentItemCode', + 'itemLevel', 'deleteFlag', 'unitOfMeasure', 'steelType', + 'gradeMaterial', 'changeDate', 'baseUnitOfMeasure' + ], + searchableFields: [ + 'itemLevel', 'itemCode', 'itemName', 'description', + 'parentItemCode', 'unitOfMeasure', 'steelType', + 'gradeMaterial', 'baseUnitOfMeasure', 'changeDate' + ], + } + }; + + return NextResponse.json(response); + + } catch (error) { + console.error("Items infinite API error:", error); + + return NextResponse.json({ + mode: 'infinite' as const, + data: [], + hasNextPage: false, + nextCursor: null, + total: 0, + error: { + message: "Failed to fetch items", + details: error instanceof Error ? error.message : 'Unknown error', + timestamp: new Date().toISOString(), + stack: process.env.NODE_ENV === 'development' ? + (error instanceof Error ? error.stack : undefined) : + undefined, + } + }, { + status: 500 + }); + } +} + +// OPTIONS 메서드로 API 정보 제공 +export async function OPTIONS() { + return NextResponse.json({ + table: 'items', + displayName: 'Package Items', + mode: 'infinite', + supportedMethods: ['GET'], + maxPageSize: 100, + defaultPageSize: 50, + + // 지원되는 모든 파라미터 + supportedParams: { + // 무한 스크롤 관련 + cursor: { type: 'string', description: 'Cursor for pagination' }, + limit: { type: 'number', description: 'Number of items per page', max: 100, default: 50 }, + + // 기본 필터 필드들 + itemCode: { type: 'string', description: 'Item code filter' }, + itemName: { type: 'string', description: 'Item name filter' }, + description: { type: 'string', description: 'Description filter' }, + parentItemCode: { type: 'string', description: 'Parent item code filter' }, + itemLevel: { type: 'number', description: 'Item level filter', default: 5 }, + deleteFlag: { type: 'string', description: 'Delete flag filter' }, + unitOfMeasure: { type: 'string', description: 'Unit of measure filter' }, + steelType: { type: 'string', description: 'Steel type filter' }, + gradeMaterial: { type: 'string', description: 'Grade material filter' }, + changeDate: { type: 'string', description: 'Change date filter' }, + baseUnitOfMeasure: { type: 'string', description: 'Base unit of measure filter' }, + + // 고급 필터링 + search: { type: 'string', description: 'Global search across all fields' }, + filters: { type: 'json', description: 'Advanced filters array' }, + joinOperator: { type: 'string', enum: ['and', 'or'], default: 'and' }, + + // 정렬 + sort: { type: 'json', description: 'Sort configuration array' }, + + // 플래그 + flags: { type: 'json', description: 'Feature flags array' }, + }, + + // 사용 예시 + examples: { + basic: '/api/table/items/infinite?limit=50', + withSearch: '/api/table/items/infinite?limit=50&search=steel', + withFilters: '/api/table/items/infinite?limit=50&itemCode=ABC&steelType=carbon', + withCursor: '/api/table/items/infinite?cursor=123&limit=50', + withSort: '/api/table/items/infinite?limit=50&sort=[{"id":"itemName","desc":false}]', + advanced: '/api/table/items/infinite?limit=50&search=test&filters=[{"id":"itemLevel","operator":"eq","value":"1"}]&joinOperator=and&sort=[{"id":"createdAt","desc":true}]' + }, + + apiVersion: '1.0', + documentation: '/docs/api/items/infinite', + compatibility: { + searchParamsCache: 'full', + dataTable: 'full', + advancedFilters: 'full', + } + }); +}
\ No newline at end of file |
