openrag/frontend/app/api/[...path]/route.ts
Cole Goldsmith d47038e097
Reorganize folders within frontend (#407)
* reorganize folder structure

* move folders from merge

* fix import issue

* run format

* update configs
2025-11-17 08:23:23 -06:00

142 lines
4.2 KiB
TypeScript

import { NextRequest, NextResponse } from "next/server";
export async function GET(
request: NextRequest,
{ params }: { params: Promise<{ path: string[] }> },
) {
return proxyRequest(request, await params);
}
export async function POST(
request: NextRequest,
{ params }: { params: Promise<{ path: string[] }> },
) {
return proxyRequest(request, await params);
}
export async function PUT(
request: NextRequest,
{ params }: { params: Promise<{ path: string[] }> },
) {
return proxyRequest(request, await params);
}
export async function DELETE(
request: NextRequest,
{ params }: { params: Promise<{ path: string[] }> },
) {
return proxyRequest(request, await params);
}
export async function PATCH(
request: NextRequest,
{ params }: { params: Promise<{ path: string[] }> },
) {
return proxyRequest(request, await params);
}
async function proxyRequest(request: NextRequest, params: { path: string[] }) {
const backendHost = process.env.OPENRAG_BACKEND_HOST || "localhost";
const backendSSL = process.env.OPENRAG_BACKEND_SSL || false;
const path = params.path.join("/");
const searchParams = request.nextUrl.searchParams.toString();
let backendUrl = `http://${backendHost}:8000/${path}${searchParams ? `?${searchParams}` : ""}`;
if (backendSSL) {
backendUrl = `https://${backendHost}:8000/${path}${searchParams ? `?${searchParams}` : ""}`;
}
try {
let body: string | ArrayBuffer | undefined = undefined;
let willSendBody = false;
if (request.method !== "GET" && request.method !== "HEAD") {
const contentType = request.headers.get("content-type") || "";
const contentLength = request.headers.get("content-length");
// For file uploads (multipart/form-data), preserve binary data
if (contentType.includes("multipart/form-data")) {
const buf = await request.arrayBuffer();
if (buf && buf.byteLength > 0) {
body = buf;
willSendBody = true;
}
} else {
// For JSON and other text-based content, use text
const text = await request.text();
if (text && text.length > 0) {
body = text;
willSendBody = true;
}
}
// Guard against incorrect non-zero content-length when there is no body
if (!willSendBody && contentLength) {
// We'll drop content-length/header below
}
}
const headers = new Headers();
// Copy relevant headers from the original request
for (const [key, value] of request.headers.entries()) {
const lower = key.toLowerCase();
if (
lower.startsWith("host") ||
lower.startsWith("x-forwarded") ||
lower.startsWith("x-real-ip") ||
lower === "content-length" ||
(!willSendBody && lower === "content-type")
) {
continue;
}
headers.set(key, value);
}
const init: RequestInit = {
method: request.method,
headers,
};
if (willSendBody) {
// Convert ArrayBuffer to Uint8Array to satisfy BodyInit in all environments
const bodyInit: BodyInit =
typeof body === "string" ? body : new Uint8Array(body as ArrayBuffer);
init.body = bodyInit;
}
const response = await fetch(backendUrl, init);
const responseHeaders = new Headers();
// Copy response headers
for (const [key, value] of response.headers.entries()) {
if (
!key.toLowerCase().startsWith("transfer-encoding") &&
!key.toLowerCase().startsWith("connection")
) {
responseHeaders.set(key, value);
}
}
// For streaming responses, pass the body directly without buffering
if (response.body) {
return new NextResponse(response.body, {
status: response.status,
statusText: response.statusText,
headers: responseHeaders,
});
} else {
// Fallback for non-streaming responses
const responseBody = await response.text();
return new NextResponse(responseBody, {
status: response.status,
statusText: response.statusText,
headers: responseHeaders,
});
}
} catch (error) {
console.error("Proxy error:", error);
return NextResponse.json(
{ error: "Failed to proxy request" },
{ status: 500 },
);
}
}