AmirHossein
AmirHossein

Reputation: 492

How to get form data in next js 13 route handler

I am using next js 13 route handler to get a login form data . I think I should be able to get it using formData method but it returns an empty object. My login page in app/login/page.jsx:

export default function Page() {
    return (
        <div>
            <form action="/api" method="post" className="...">
                <input type="text" name="username" id="username" className="..." />
                <input type="password" name="password" id="username" className="..." />
                <input type="submit" id="submit" value="submit" className="..." />
            </form>
        </div>
    )
}

and app/api/route.js:

import { NextResponse } from 'next/server';

export async function POST(request):
    const data = request.formData();
    return NextResposne.json({ data })

and this is my response after submitting the form:

{"data":{}}

Any idea ? thanks

Upvotes: 7

Views: 14955

Answers (7)

Aras Ors
Aras Ors

Reputation: 1

I solved it this way

export async function POST(req) {
    try {
        const formData = await req.formData();
        const file = formData.get('file'); // or what you need
        const buffer = Buffer.from(await file.arrayBuffer());

        // ready your file on buffer
        
        

    } catch (error) {
        return NextResponse.json({ error: error });
    }
}

Upvotes: 0

MDompekidis
MDompekidis

Reputation: 353

If you are like me and you are using app-router but your API lives in pages/api then the only way I found that works, is to send the file as base64 string. Decode into a Buffer, create a new form-data and send it. The whole file looks like this:

import { API_ENDPOINTS } from '@/API/api';
import { ironOptions } from '@/config/iron-config';
import { AuthData } from '@/models/AuthData';
import { getIronSession } from 'iron-session';
import { NextApiRequest, NextApiResponse } from 'next';
import fetch from 'node-fetch';
import FormData from 'form-data';

export default async function handler(req: NextApiRequest, res: NextApiResponse) {
  const session = await getIronSession<AuthData>(req, res, ironOptions);
  const body = req.body;
  //

  //Convert Base64 to Buffer
  const buffer = Buffer.from(JSON.parse(body).file, 'base64');
  // Create a new FormData instance
  const formData = new FormData();
  formData.append('file', buffer);

  //
  let url = `${API_ENDPOINTS['upload_media'].url}`;
  let method = API_ENDPOINTS['upload_media'].type;
  var myHeaders = new Headers();
  myHeaders.append('Authorization', `JWT ${session.token}`);
  myHeaders.append('Content-Type', formData.getHeaders()['content-type']);

  // get user from database then:
  const response = await fetch(url, {
    method: method,
    headers: myHeaders,
    body: formData,
  });

  // if error return the error
  const data = await response.json();
  if (response.status >= 400) return res.status(response.status).json(data);

  return res.status(response.status).json(data);
}

On the client side you can do the following to get the base64:

 function getBase64(file: File) {
   var fileReader = new FileReader();
   if (file) {
     fileReader.readAsDataURL(file);
   }
   return new Promise<string | null>((resolve, reject) => {
     fileReader.onload = function (event: any) {
       resolve(event?.target?.result);
     };
   });
 }

 const reader = new FileReader();
 reader.onload = (e: any) => {
    setSelectedFile(e.target.result);
 };
 reader.readAsDataURL(event.target.files[0]);
 let result: string | null = await getBase64(event.target.files[0]);

Upvotes: -1

Niyaz
Niyaz

Reputation: 927

Try this:

export const config = {runtime: 'edge'};

export default async function POST(request) {

    const formData = await request.formData()
    const name = formData.get('name')//get name property

    return NextResponse.json({ name })
}

Upvotes: 0

mundane
mundane

Reputation: 1

you should await it, like this:

const data = await request.formData();

Upvotes: -1

Ryan
Ryan

Reputation: 24073

The Nextjs docs were terrible and didn't clarify this.

After lots of trial and error, I finally found that this works:

import { type NextRequest } from 'next/server';
// ...

export async function POST(request: NextRequest) {
  const data = await request.json();
  console.log({ data });
  // ...
}

Note: Use NextRequest instead of NextApiRequest.

Upvotes: 1

Nilanjan
Nilanjan

Reputation: 111

This is working on my side and I am using js not ts.

import { NextResponse } from 'next/server'



export async function POST(request) {
//   return NextResponse.json({ data: "working fine" })
const formData = await request.formData()
const name = formData.get('name')
const email = formData.get('email')
const myfile = formData.get('myfile')
console.log(myfile);
return NextResponse.json({ name, email })

}

Upvotes: 4

Yilmaz
Yilmaz

Reputation: 49571

.formData returns Promise

(method) Body.formData(): Promise<FormData>

You should await it:

const data = await request.formData();

Upvotes: 0

Related Questions