Next.js 13 DELETE request 'SyntaxError: Unexpected end of JSON input'

1.1k Views Asked by At

I have a web app using Next 13 with a route.ts file under the api folder that currently contains 2 different methods POST and DELETE.

Both methods receive the request successfully but when trying to JSON parse the body of the request, it works for the POST but not for the DELETE, even though I'm performing the exact same steps.

I checked the request in the 'Network' tab of the dev tools and the payload is fine. what am I missing?

This is the Error:

SyntaxError: Unexpected end of JSON input
    at JSON.parse (<anonymous>)
    at NextRequest.json (node:internal/deps/undici/undici:6160:23)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
    at async DELETE (webpack-internal:///(sc_server)/./app/api/workPlace/route.ts:35:22)
    at async eval (webpack-internal:///(sc_server)/./node_modules/next/dist/server/future/route-modules/app-route/module.js:242:37)

The DELETE request body should contain a json with one property - array of strings. Frontend as follows:

export async function fetchRemoveWorkPlaces(ids: string[]) {
    const data = { ids: ids }
    const response = await fetch(
        '/api/workPlace', 
        {
            method: 'DELETE',
            headers: {'Content-Type': 'application/json'},
            body: JSON.stringify(data)
        }
    )
  }

This is the route.ts in the server:

export async function POST(req: Request, res: NextResponse , context: {}) {
    
    try {
        const body: any = await req.json()
        const response = await workPlaceDao.addWorkPlace(body)

        return NextResponse.json(
            {
                success: true,
                workPlace: response
            }, 
            { status: 200 })
    } catch (e) {
        console.log('Error occurred while Add Work Place Request');
        console.log(e);
        return NextResponse.json({success: false}, { status: 500 })
    }
}
export async function DELETE(req: Request, res: NextResponse , context: {}) {

    try {
        const body: any = await req.json()
        const response = await workPlaceDao.deleteWorkPlace(body.ids)

        return NextResponse.json(
            {
                success: true,
            }, 
            { status: 200 })
    } catch (e) {
        console.log('Error occurred trying to delete Work Places');
        console.log(e);
        return NextResponse.json({success: false}, { status: 500 })
    }
}
3

There are 3 best solutions below

0
Dreams Nguyen On

It is a known bug and has been addressed (though not much progress has been made)

  • You can read more of it here: https://github.com/vercel/next.js/issues/53882

  • For a quick workaround, we just have to do it the old-fashioned way (alias-ing). In short, the two that can work nicely currently are GET/POST.

  • For your hook to call the REST API

export async function fetchRemoveWorkPlaces(ids: string[]) {
    const data = { ids: ids }
    const response = await fetch(
        '/api/workPlace2',  // Change it to something similar
        {
            method: 'DELETE',
            headers: {'Content-Type': 'application/json'},
            body: JSON.stringify(data)
        }
    )
  }

and then slap the delete code in the newly acquired "POST" request

export async function POST(req: Request, res: NextResponse , context: {}) {
    
   try {
        const body: any = await req.json()
        const response = await workPlaceDao.deleteWorkPlace(body.ids)

        return NextResponse.json(
            {
                success: true,
            }, 
            { status: 200 })
    } catch (e) {
        console.log('Error occurred trying to delete Work Places');
        console.log(e);
        return NextResponse.json({success: false}, { status: 500 })
    }
}

1
Hugo On

DELETE requests usually don't include a body, so you can send the IDs up in query params instead on the frontend:

export async function fetchRemoveWorkPlaces(ids: string[]) {
    const response = await fetch(
        `/api/workPlace?ids=${JSON.stringify(ids)}`, 
        {
            method: 'DELETE',
            headers: {'Content-Type': 'application/json'},
        }
    );
}

On the server side, read the query parameters instead of trying to parse the body:

export async function DELETE(req: Request, res: NextResponse , context: {}) {

    try {
        const ids: string[] = JSON.parse(req.query.ids as string); // Parse the query parameter

        const response = await workPlaceDao.deleteWorkPlace(ids);

        return NextResponse.json(
            {
                success: true,
            }, 
            { status: 200 });
    } catch (e) {
        console.log('Error occurred trying to delete Work Places');
        console.log(e);
        return NextResponse.json({success: false}, { status: 500 });
    }
}
0
Russo On

in your NextJs frontend:

await axios.delete(`/api/item`, { params: { id } })

in your NextJs backend: /api/item/route.ts

export async function DELETE(req: Request) {
  console.log("DELETE", req, req.url);
  const id = req.url.split('=')[1];
  ...
}