/** * Development proxy configuration * Useful for proxying external APIs during development */ import { NextRequest, NextResponse } from 'next/server' export interface ProxyConfig { target: string pathRewrite?: Record changeOrigin?: boolean headers?: Record } /** * Simple proxy utility for API routes * @param request - The incoming request * @param config - Proxy configuration */ export async function proxyRequest( request: NextRequest, config: ProxyConfig ): Promise { try { const url = new URL(request.url) let targetPath = url.pathname // Apply path rewrites if (config.pathRewrite) { Object.entries(config.pathRewrite).forEach(([pattern, replacement]) => { const regex = new RegExp(pattern) if (regex.test(targetPath)) { targetPath = targetPath.replace(regex, replacement) } }) } // Build target URL const targetUrl = new URL(targetPath + url.search, config.target) // Prepare headers const headers = new Headers() // Copy headers from original request request.headers.forEach((value, key) => { // Skip host header to avoid conflicts if (key.toLowerCase() !== 'host') { headers.set(key, value) } }) // Add custom headers if (config.headers) { Object.entries(config.headers).forEach(([key, value]) => { headers.set(key, value) }) } // Change origin if specified if (config.changeOrigin) { headers.set('Host', targetUrl.host) headers.set('Origin', config.target) } // Forward the request const response = await fetch(targetUrl.toString(), { method: request.method, headers, body: request.method !== 'GET' && request.method !== 'HEAD' ? await request.arrayBuffer() : undefined, }) // Create response with proper headers const responseHeaders = new Headers() // Copy response headers response.headers.forEach((value, key) => { // Skip some headers that might cause issues if ( !['content-encoding', 'content-length', 'transfer-encoding'].includes(key.toLowerCase()) ) { responseHeaders.set(key, value) } }) // Add CORS headers for development if (process.env.NODE_ENV === 'development') { responseHeaders.set('Access-Control-Allow-Origin', '*') responseHeaders.set('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS') responseHeaders.set('Access-Control-Allow-Headers', 'Content-Type, Authorization') } const responseBody = await response.arrayBuffer() return new NextResponse(responseBody, { status: response.status, statusText: response.statusText, headers: responseHeaders, }) } catch (error) { console.error('Proxy error:', error) return NextResponse.json({ error: 'Proxy request failed' }, { status: 500 }) } } /** * Example usage in an API route: * * // app/api/proxy/external/route.ts * import { proxyRequest } from '@/lib/proxy'; * * export async function GET(request: NextRequest) { * return proxyRequest(request, { * target: 'https://api.external-service.com', * pathRewrite: { * '^/api/proxy/external': '' * }, * changeOrigin: true, * headers: { * 'X-API-Key': process.env.EXTERNAL_API_KEY || '' * } * }); * } */