127 lines
3.4 KiB
TypeScript
127 lines
3.4 KiB
TypeScript
/**
|
|
* Development proxy configuration
|
|
* Useful for proxying external APIs during development
|
|
*/
|
|
|
|
import { NextRequest, NextResponse } from 'next/server'
|
|
|
|
export interface ProxyConfig {
|
|
target: string
|
|
pathRewrite?: Record<string, string>
|
|
changeOrigin?: boolean
|
|
headers?: Record<string, string>
|
|
}
|
|
|
|
/**
|
|
* Simple proxy utility for API routes
|
|
* @param request - The incoming request
|
|
* @param config - Proxy configuration
|
|
*/
|
|
export async function proxyRequest(
|
|
request: NextRequest,
|
|
config: ProxyConfig
|
|
): Promise<NextResponse> {
|
|
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 || ''
|
|
* }
|
|
* });
|
|
* }
|
|
*/
|