File Upload Issue: POST request won't hit API server
Answered
Gharial posted this in #help-forum
GharialOP
Context: Website uploads user's audio file to a separate inference API for model. The uploaded audio file is processed into an embedding and returned to the NextJS client.
To avoid CORS issues and having to use proxy requests, I am moving all API calls to NextJS server-side using Route handlers. I have an endpoint on the inference API called
It takes a multipart request, and was working when making proxied requests on the client side. It now seems sending the file from client --> server --> model API is corrupting the formData. The request from the nextjs server never makes it to the model API, it's strange.
To avoid CORS issues and having to use proxy requests, I am moving all API calls to NextJS server-side using Route handlers. I have an endpoint on the inference API called
POST /api/embeddingsIt takes a multipart request, and was working when making proxied requests on the client side. It now seems sending the file from client --> server --> model API is corrupting the formData. The request from the nextjs server never makes it to the model API, it's strange.
// app/demo/ModelTester.tsx
// logic to create embedding with an audio file
const getEmbeddings = async () => {
if (!file) return;
const data = new FormData();
data.append("file", file);
data.append("fileName", file.name);
// fetch embeddings via POST to nextjs server
const url = "/api/embeddings";
const options = {
method: "POST",
body: data,
};
const embeddings = await fetch(url, options);
return await embeddings.json();
}; // app/api/embeddings/route.ts
import { NextRequest, NextResponse } from "next/server";
import apiURLPrefix from "@/utils/url";
export async function POST(request: NextRequest) {
const url = apiURLPrefix + "embeddings";
const data = await request.formData();
const options = {
method: "POST",
body: data,
};
try {
const res = await fetch(url, options);
const resData = await res.json();
const embeddings = resData.embeddings;
return NextResponse.json(embeddings);
} catch (err) {
console.log(err);
return NextResponse.json({ error: true });
}
}Answered by Gharial
Updated code
// client logic
const getEmbeddings = async () => {
if (!file) return;
const data = new FormData();
data.append("file", file);
data.append("fileName", file.name);
// fetch embeddings
const url = "/api/upload";
const options = {
method: "POST",
body: data,
};
const embeddings = await fetch(url, options);
return await embeddings.json();
};// route.ts
import { NextRequest, NextResponse } from "next/server";
import apiURLPrefix from "@/utils/url";
import axios from "axios";
import { writeFile } from "fs";
import FormData from "form-data";
export async function POST(request: NextRequest) {
const url = apiURLPrefix + "embeddings";
// convert MDN formData --> form-data
// 1. get old formData
const data = await request.formData();
const file = data.get("file") as File;
// init new FormData with form-data, append file values
const reqFormData = new FormData();
const ab = await file.arrayBuffer();
const buffer = Buffer.from(ab);
reqFormData.append("file", buffer, file.name);
try {
const embeddings = await axios.post(url, reqFormData).then((res) => {
return res.data.embeddings;
});
return NextResponse.json(embeddings);
} catch (err) {
console.log("Error while generating embeddings in nextJS backend: ", err);
return NextResponse.json({ error: true });
}
}21 Replies
GharialOP
What could the issue be here? I have already attempted to follow this discussion, https://github.com/vercel/next.js/discussions/39957, with no success.
It seems like the file is being modified in between the client to server on nextjs. The
File stored on the formdata share different dates under the lastModified. Weird.Also, fyi, again, the request never makes it to the model API. The code seems to freeze at the fetch line in the POST() server code. I will try using a debugger
double check your url
const url = apiURLPrefix + "embeddings";without seeing the rest of the variable
my first guess is you're missing a
/ in apiURLPrefixGharialOP
nope there is a / there
This is a slightly modified version of the code but I've printed it out and it comes out with / there
I have other endpoints that work, it's just this one with the file upload, that does not work
Something interesting if remove the formData in
The model API receives the request but obiv returns a 422 since it expects a file.
options// api/embeddings/route.ts
const options = {
method: "POST",
// body: data,
};The model API receives the request but obiv returns a 422 since it expects a file.
European sprat
Don't you have to do
data.get("file")GharialOP
@European sprat nope, this just gets you the file object but you still need to pass it as formdata
I am suspecting its the cache/revalidation that happens with POST requests on next side
GharialOP
:/ nah turning off revalidation did not help
European sprat
Ok but as a test can get get the file and save it to disk
Don't try passing it to the other API yet just confirm you can actually get the file
GharialOP
Yes, I can save it to disk and it is the same file
GharialOP
I got something working, two things.
1. Convert file to buffer
2. don't use MDN library in the nextjs api server.
Don't ask me the whys, I have not recollected myself to understand yet lol, but I noticed that worked for the guy in the github discussion above.
1. Convert file to buffer
2. don't use MDN library in the nextjs api server.
Don't ask me the whys, I have not recollected myself to understand yet lol, but I noticed that worked for the guy in the github discussion above.
GharialOP
Updated code
// client logic
const getEmbeddings = async () => {
if (!file) return;
const data = new FormData();
data.append("file", file);
data.append("fileName", file.name);
// fetch embeddings
const url = "/api/upload";
const options = {
method: "POST",
body: data,
};
const embeddings = await fetch(url, options);
return await embeddings.json();
};// route.ts
import { NextRequest, NextResponse } from "next/server";
import apiURLPrefix from "@/utils/url";
import axios from "axios";
import { writeFile } from "fs";
import FormData from "form-data";
export async function POST(request: NextRequest) {
const url = apiURLPrefix + "embeddings";
// convert MDN formData --> form-data
// 1. get old formData
const data = await request.formData();
const file = data.get("file") as File;
// init new FormData with form-data, append file values
const reqFormData = new FormData();
const ab = await file.arrayBuffer();
const buffer = Buffer.from(ab);
reqFormData.append("file", buffer, file.name);
try {
const embeddings = await axios.post(url, reqFormData).then((res) => {
return res.data.embeddings;
});
return NextResponse.json(embeddings);
} catch (err) {
console.log("Error while generating embeddings in nextJS backend: ", err);
return NextResponse.json({ error: true });
}
}Answer