2 * Example API Route Using Session Context
4 * This demonstrates the proper pattern for creating API routes that:
5 * 1. Check authentication from session
6 * 2. Route to correct store URL based on session
7 * 3. Handle different request types (openapi, gnap, elink)
8 * 4. Enforce security: Retail stores can ONLY use ELINK
11import { NextRequest, NextResponse } from "next/server";
12import { getRequestContext, validateStoreAccess, getStoreApiUrl, validateApiAccess } from "@/lib/server/sessionUtils";
13import { FieldpineServerApi } from "@/lib/server/fieldpineApi";
16 * GET /api/v1/example-session
17 * Example endpoint demonstrating session-based routing with security
19export async function GET(request: NextRequest) {
21 // 1. Get session and store context
22 const context = await getRequestContext(request);
25 return NextResponse.json(
26 { success: false, error: "Unauthorized - Please log in" },
31 // 2. SECURITY: Validate API access based on store type
32 // Retail stores can ONLY use ELINK, management portal can use all
33 const apiAccessValidation = validateApiAccess(context, 'elink');
34 if (!apiAccessValidation.valid) {
35 console.warn(`[API Security] Access denied: ${apiAccessValidation.error}`);
36 return NextResponse.json(
39 error: apiAccessValidation.error,
40 code: apiAccessValidation.errorCode
46 // 3. Validate store type if needed (optional)
47 // For example, if this endpoint only works in retail stores:
48 const validation = validateStoreAccess(context, 'store');
49 if (!validation.valid) {
50 return NextResponse.json(
51 { success: false, error: validation.error },
56 // 4. Get the appropriate API URL for the request type
57 // Retail stores: ONLY 'elink' is allowed
58 // Management portal: Can use 'openapi', 'gnap', or 'elink'
59 const apiUrl = getStoreApiUrl(context, 'elink');
61 // 5. Create Fieldpine API client with store-specific URL
62 const api = new FieldpineServerApi(apiUrl);
64 // 6. Make API calls using the session's API key
67 "3": "retailmax.elink.products",
69 "99": Math.random().toString()
71 const response = await api.buckApiCall(buckParams, context.session.apiKey);
74 return NextResponse.json({
78 store: context.store.name,
79 storeType: context.store.type,
81 user: context.session.username,
82 allowedEndpoints: context.isRetailStore ? ['ELINK only'] : ['OpenAPI', 'GNAP', 'ELINK']
86 } catch (error: any) {
87 console.error("[Example Session API] Error:", error);
88 return NextResponse.json(
89 { success: false, error: error.message || "Internal server error" },
96 * Example demonstrating management portal access to GNAP
97 * This will be BLOCKED for retail stores
99export async function POST(request: NextRequest) {
101 const context = await getRequestContext(request);
104 return NextResponse.json(
105 { success: false, error: "Unauthorized" },
110 // SECURITY: Validate GNAP access (retail stores will be BLOCKED)
111 const apiAccessValidation = validateApiAccess(context, 'gnap');
112 if (!apiAccessValidation.valid) {
113 console.warn(`[API Security] GNAP access denied for retail store: ${context.store.name}`);
114 return NextResponse.json(
117 error: apiAccessValidation.error,
118 code: apiAccessValidation.errorCode,
119 hint: 'GNAP endpoints are restricted to management portal only'
125 // GNAP requests always go to IIG management portal
126 const gnapUrl = getStoreApiUrl(context, 'gnap');
127 const api = new FieldpineServerApi(gnapUrl);
129 // Example BUCK call for reports
131 "3": "retailmax.report.sales",
133 "99": Math.random().toString()
136 const response = await api.buckApiCall(buckParams, context.session.apiKey);
138 return NextResponse.json({
144 store: context.store.name,
145 note: 'This endpoint is only accessible from management portal'
149 } catch (error: any) {
150 console.error("[Example GNAP API] Error:", error);
151 return NextResponse.json(
152 { success: false, error: error.message },