1

I am having trouble with making an API call in Next.js that is deleting an item in a database. I am using the "body" field of the fetch to send a string to the API. The fetch call is being made in a Next.JS page and the API endpoint is in the API folder generated by Next.js. When I attempt the console.log the body from the request it is returning an empty object. Below will be the code for the page and then the code for the API endpoint. A screenshot of the console.log from the API endpoint will also be given.

Page

   const handleRemoveItem = useCallback(async(event) => {
        event.preventDefault()
        
        var itemSKU = event.target.value;

        const response = await fetch('/api/SB-RemoveProduct', {
            method:'POST',
            body: itemSKU
            }).then((r) => {
              return r
            }).catch((err) => {
              throw(err)
            });
        var deleteConfirm = await response.json();

        console.log(deleteConfirm);
    },[])

API endpoint

export default withSession(async (req, res) => {
    var itemSKU = req.body

    console.log("You are here 1");
    console.log(itemSKU);

    switch (req.method) {
        case 'POST': {
            var productRemoved = await removeProduct(itemSKU, req, res)
            return productRemoved;
            break
        }
        case 'GET': {
            console.log('try writting a route')
            break
        }
        case 'DELETE': {
            console.log('try writting a route')
            break
        }
        case 'UPDATE': {
            console.log('try writting a route')
            break
        }
    }

});

export const removeProduct = async (itemSKU, req, res) => {

    var params = {
        TableName: "products",
        Key: itemSKU
    }
    console.log("You are here 2");
    console.log(itemSKU); // this console.log and the one above both return {}
    DB.delete(params, function(err, data) {
        if (err) {
            console.error("Unable to delete item. Error JSON:", JSON.stringify(err, null, 2));
        } else {
            console.log("DeleteItem succeeded:", JSON.stringify(data, null, 2));
            res.status(200).send(data)
        }
    });
    
}

enter image description here

EDIT 1:

After receiving some feedback, I added headers with the 'Content-Type': 'text/plain', 'Accept': 'text/plain' and ended with the same result. I also verified that the variable that I am passing into the body is a string. Below will be page for the code updated.

    const handleRemoveItem = useCallback(async(event) => {
        event.preventDefault()
        
        var itemSKU = event.target.value;
        console.log(typeof(itemSKU));

        const response = await fetch('/api/SB-RemoveProduct', {
            method:'POST',
            body: itemSKU,
            mode: "cors",
            headers: {
                'Accept': 'text/plain',
                'Content-Type': 'text/plain'
              },
            }).then((r) => {
              return r
            }).catch((err) => {
              throw(err)
            });
        var deleteConfirm = await response.json();

        console.log(deleteConfirm);
    },[])

EDIT 2:

Following the suggestions from a solution below, I was able to return a different value for itemSKU than what I had before. This time, instead of the item being empty, it returned as undefined. The changes I made are below:

page:

const handleRemoveItem = useCallback(async(event) => {
        event.preventDefault()
        
        var itemSKU = event.target.value;
        console.log(typeof(itemSKU));

        const response = await fetch('/api/SB-RemoveProduct', {
            method:'POST',
            body: JSON.stringify({itemSKU}),
            }).then((r) => {
              return r
            }).catch((err) => {
              throw(err)
            });
        var deleteConfirm = await response.json();

        console.log(deleteConfirm);
    },[])

API Endpoint:

export default withSession(async (req, res) => {
    var itemSKU = req.body.itemSKU //req.body.itemSKU is returning undefined.

    console.log("You are here 1");
    console.log(itemSKU);

    switch (req.method) {
        case 'POST': {
            var productRemoved = await removeProduct(itemSKU, req, res)
            return productRemoved;
            break
        }
        case 'GET': {
            console.log('try writting a route')
            break
        }
        case 'DELETE': {
            console.log('try writting a route')
            break
        }
        case 'UPDATE': {
            console.log('try writting a route')
            break
        }
    }

});

export const removeProduct = async (itemSKU, req, res) => {

    var params = {
        TableName: "products",
        Key: itemSKU
    }
    console.log("You are here 2");
    console.log(itemSKU);
    // DB.delete(params, function(err, data) {
    //     if (err) {
    //         console.error("Unable to delete item. Error JSON:", JSON.stringify(err, null, 2));
    //     } else {
    //         console.log("DeleteItem succeeded:", JSON.stringify(data, null, 2));
    //         res.status(200).send(data)
    //     }
    // });
    
}
Shafi Kamal
  • 91
  • 3
  • 10
  • 1
    You're sending a `text/plain` request body. Is that what you're wanting to send? Is the API configured to handle such a request content-type? – Phil Feb 15 '22 at 04:47
  • So normally I would use JSON.stringify() when passing information to the request body, but doing so returns the exact same result. – Shafi Kamal Feb 15 '22 at 05:17
  • You would also need to set the appropriate content-type header – Phil Feb 15 '22 at 05:19
  • Sorry, I am still a pretty novice dev, do you mind explaining the content-type header and what I would need to change it to? – Shafi Kamal Feb 15 '22 at 05:57
  • See [this answer](https://stackoverflow.com/a/39565776/283366) – Phil Feb 15 '22 at 06:00
  • I added headers with the 'Content-Type': 'text/plain', 'Accept': 'text/plain' and ended with the same result. The item that I am passing to the body is just a plain string, so wouldn't text/plain be the value to use here? Sorry if I am missing something. – Shafi Kamal Feb 15 '22 at 06:26
  • Back to my first question then, is your API expecting that? – Phil Feb 15 '22 at 06:54
  • I guess I may be confused on how my API would expect that. I am not sure on how I can tell if my API is expecting a type of value or not. – Shafi Kamal Feb 15 '22 at 15:02

1 Answers1

3

remove the headers, including Content-type: plain/text, then...

In your request, change

body: itemSKU,

to

body: JSON.stringify({ itemSKU });

In your API, you can

console.log('req.body.itemSKU', req.body.itemSKU)

Eventually...

//client side
fetch('/api/...', { method: 'POST', body: JSON.stringify({...}))
.then(res => res.json())
.then(data => console.log('data', data)); 
//prints { value1: 'abc', value2: 'efg'}

Then on API side

export default async(req, res) => {

       console.log('req.body.itemSKU', req.body.itemSKU);

       res.json({ value1: 'abc', value2: 'efg'})
}
Someone Special
  • 12,479
  • 7
  • 45
  • 76
  • I tried using this method, and I actually got a value of undefined instead. – Shafi Kamal Feb 15 '22 at 14:57
  • It will be better if every response is clear and precise. Precisely, what is undefined? `req.body.itemSKU` ? Did you try to console.log(req.body) and see what it contains? Did you remove all the headers (e.g. content-type) like advised? – Someone Special Feb 15 '22 at 15:21
  • https://codesandbox.io/s/musing-paper-rf5vym?file=/pages/index.js see the console.log in both terminal and console. – Someone Special Feb 15 '22 at 16:15
  • I made an edit in the original post of what was being returned as undefined. It was req.body.itemSKU. I do not see a major difference in the requests that is in the code sandbox and mine. I use the same method and values for the body. – Shafi Kamal Feb 15 '22 at 16:33
  • Since the code u shown, and the codes in sandbox are identical and you are still facing the same problem then problem is not with the codes, you agree? It is likely, that you have some middle ware, that is interferring with how NextJS processes all request as application/json by default. You can try to check the req.headers for the content-type – Someone Special Feb 15 '22 at 16:35
  • 1
    I was able to resolve the issue, the middleware was fine and was not the cause. Adding the content type headers with the values of application/json resolved the issue. However, I think my original issue was not wrapping itemSKU around curly brackets when using the .stringify function. – Shafi Kamal Feb 15 '22 at 16:52
  • If you need to add "application/json" in your fetch request, that means you have middleware that changed the default parser, otherwise nextjs parse it as application/json by default. Nevertheless, good that your problem is solved. – Someone Special Feb 15 '22 at 17:06
  • @SomeoneSpecial no, if you're sending JSON with `fetch`, you should definitely set the appropriate content-type header – Phil Feb 15 '22 at 20:17
  • @Phil nextjs default api if you stringify your request, and send it as text/plain, it will also be parsed as json. u can checkout the codesandbox above – Someone Special Feb 16 '22 at 03:17
  • My comment was more general; your request content-type header should match the body format. It's a good practice to get into since most server-side frameworks require it – Phil Feb 16 '22 at 03:20
  • Can you post your solution for this. Not in the comments please – Taio Apr 04 '23 at 12:13