Doc inconsistencies around responses and basic function template

Happy Netlify customer here for many years.

It looks like Netlify docs & functions are in the middle of a transition? Which really stinks if you are a newbie coming in and trying out Functions functionality.

I just spent an evening and a morning trying to figure out how to return a status code using the default recommended function template:

All of the docs show this:

export default async (req, context) => {
  return new Response("Hello, world!");
};

(Link: Get started with functions | Netlify Docs)

Which appears to be the new blessed way to do this.

But if you go through the rest of the docs, the following format is used:

const handler: Handler = async function (event: HandlerEvent, context: HandlerContext) {
   //...
}

And if you aren’t paying close attention, you’ll miss that. It’s cognitive overload that one doesn’t need when you are scanning info on how to do something: “Is this the old way or the new way?”

Now to the point: how do you return a 404 status code along with some JSON?

Well, looking at the Netlify docs, it’s quite obviously:

return {
  body: JSON.stringify({}),
  statusCode: 404
}

And, that’s also further cemented as the way according to all the searches here on answers.netlify.com and google.com

But it’s not. It’s:

return new Response(JSON.stringify({}), { status: 404 });

(Which I only figured out by going through Mozilla developer docs: Response: Response() constructor - Web APIs | MDN)

And to my last point, finding out WHY you are getting a blank 500 error code with absolutely no exception thrown, no error message, nothing in the logs on development and production is really, really frustrating.

It appears (and maybe this was stated in the docs some place that I missed) that if you access the function locally in a browser, instead of via a JS fetch or RapidAPI test call, you will get an HTML page that explains more and includes a stack trace.

But why oh why isn’t that message shown in the local CLI logs? I only stumbled upon this by accident.

Some of this is me venting. But mostly this is feedback to improve the docs and also for anyone else that comes through here in the future trying to find out how to return a response with a status code from a Function.

Further:

How do you use JSON sent to a function?

Do you read it from the body?

let body = JSON.parse(req.body);

No, that kills the function. (Also, in my testing, it kills it so hard that 9 of 10 console.log statements are not shown in the cli logs. Which, again, is problematic if you are use logging to debug problems.)

So what is req.body? Can I just output the value?

console.log(req.body);

Yields exactly nothing. A blank. Even if the body did actually have content.

So from here one would search something like “netlify function request body is always blank” and you would get a list of forum posts here that talk about a bug in the CLI or improperly formatted JSON. A lot of posts that lead you to believe there is something wrong outside of your function code.

But that’s wrong. Buried in one of those posts is:

And reading there, you finally find the answer:

req.json()

The answer refers to a Netlify blog post describing the change. Why isn’t this referring to the docs instead? Blog posts aren’t coming up in searches for dev issues.

A lot of this post, as you mentioned, seems for venting. This is less of a help me troubleshoot post and more of frustration due to hours spent. While I understand that, I’m sorry to be the person to blame this (at least partially) on the user.

I’d have taken this feedback, but this does look like a reading error on your end. I could be wrong and I’d be happy to learn more about the exact pieces of docs you found with the issue, which currently you have not linked.

This part is correct.

I found that section in Functions and Identity section: Functions and Identity | Netlify Docs, which is not somewhere a user who doesn’t use Identity would go. Furthermore, that’s the only way to use Functions + Identity, so this is at least not a case of incorrect documentation. If you found the old syntax elsewhere, we can get that updated.

This is documented Get started with functions | Netlify Docs:

The handler function should return a Response object representing the HTTP response to be delivered to the client.

We switched to a web-standard specifically so that you don’t have to learn Netlify-specific concepts. Response has a json method: Response: json() static method - Web APIs | MDN (mozilla.org), and the options accept a status code: Response: json() static method - Web APIs | MDN (mozilla.org). This is how it can be put together:

return Response.json({
  msg: 'not-found'
}, {
  status: 404
})

Source?

We had the Lambda API from 2019-2023. It’s not a surprise most of the old posts still show that as it’s not possible to update every post with the new syntax.

That’s the expectation, as mentioned above.

This would be something we would have to investigate, but that sounds more of a complaint than asking for help with troubleshooting.

The stacktrace also exists when using fetch.

It’s standard JavaScript, not something specific to Netlify. Fetch depends on Request/Response. How do you read JSON in fetch? It’s basically the same.

If you’re expecting Netlify to document something that’s already documented by MDN as a Web Standard, I don’t think we have any plans to do that. If we have mentioned that the request argument is the Web Standard Request interface, that should explain the rest.

For the logging issue:

When using the netlify dev command to run locally, the problem is that it’s possible in Function code for console.log to not output anything even though execution passes that line of code.

Further, the problem is that an exception is thrown, but the exception is swallowed somewhere down lower and not shown to the end developer in the terminal output.

Here is a sample test case where console.log fails to go to CLI output:

netlify/funtions/hello.mjs:

export default async (req, context) => {
    console.log("First line");
    console.log("Second line");
    console.log("Third line");
    console.log("Fourth line");
    console.log("Fifth line");

    JSON.parse(req.body); // this is valid javascript, but as discussed, doesn't work, that's not the point here though.

    return new Response("What happened to the logs?");
};

src/pages/index.astro:

<script>
    window.addEventListener('load', function () {
        fetch("/.netlify/functions/hello", {
            method: "POST",
            body: JSON.stringify({
                word: "to your mother"
            })
        });
    });
 </script>

Expected netlify dev terminal output:

Request from ::1: GET /.netlify/functions/hello
First line
Second line
Third line
Fourth line
Fifth line
Exception raised: [error message]
     [stack trace]
Response with status 500 in 273 ms.

Actual:

Request from ::1: POST /.netlify/functions/hello
First line
Response with status 500 in 316 ms.

Zip of minimal Astro project:
Missing console log example.zip (84.2 KB)

  1. Extract zip
  2. Run yarn install
  3. Run ntl dev
  4. Open index in browser and check the console output as well as terminal output.

That’s not valid JavaScript. Syntax-wise, it is, functionality-wise it’s not. req.body is a stream, not a JSON string. I’d recommend you to read about Request and Response from MDN docs.

As for the issue reported, this appears to be a bug. I’ve filed it for the devs.

The issue has been identified to be a Node.js limitation: github.com/nodejs/node/issues/40961