25

With Azure Functions, what do you need to do to return a JSON object in the body from a function written in node.js? I can easily return a string, but when I try to return a json object as shown below I appear to have nothing returned.

context.res = {
   body: jsonData,
   contentType: 'application/json'
};
Peter Pan
  • 23,476
  • 4
  • 25
  • 43
Chris Dellinger
  • 2,292
  • 4
  • 25
  • 33
  • 1
    Also note that to specify the content type of the response, you do that via the headers collection on the response, e.g. `context.res.headers = { 'Content-Type': 'text/plain' }`. As David says below, we'll default that to application/json for you if your response is json. – mathewc May 11 '16 at 15:15

6 Answers6

47

Based on my recent testing (March 2017). You have to explicitly add content type to response headers to get json back otherwise data shows-up as XML in browser.

"Content-Type":"application/json"

res = {
    status: 200, /* Defaults to 200 */
    body: {message: "Hello " + (req.query.name || req.body.name)},
    headers: {
        'Content-Type': 'application/json'
    }
};

Full Sample below:

module.exports = function (context, req) {
    context.log('JavaScript HTTP trigger function processed a request.');
    context.log(context);

    if (req.query.name || (req.body && req.body.name)) {
        res = {
            // status: 200, /* Defaults to 200 */
            body: {message: "Hello " + (req.query.name || req.body.name)},
            headers: {
                'Content-Type': 'application/json'
            }
        };
    }
    else {
        res = {
            status: 400,
            body: "Please pass a name on the query string or in the request body"
        };
    }
    context.done(null, res);
};
Shiva
  • 20,575
  • 14
  • 82
  • 112
spooky
  • 1,620
  • 1
  • 13
  • 15
  • 1
    where I should put this code? I'm trying to override my table.read(context). I have a json object that I got from my sql query (I joined two tables). But I don't know how to return this. =/ – rafaelbpa Jun 13 '17 at 20:00
  • 2
    This helped me realize that chrome was sending accept headers that must not have jived with what the function was returning. Along with Allen Underwood's input, I now realize that I should pretty much just not use chrome to test the api. postman works great. – Brandon Wittwer Jul 26 '17 at 16:50
  • this does not work for me. Does not return application/json, neither a message back. – toto' Aug 14 '20 at 15:56
  • Still works. the `body` can take json object, however, the `headers` key should be all lowercase. – Abu Sufian Jan 27 '23 at 00:48
  • As of Mar 2023, this is still the only way that works. Some other answers and even the docs say that Azure should "just work" if you return an object as the body, but it's not working. – Lavamantis Mar 02 '23 at 23:17
12

If your data is a JS object, then this should just work, e.g.

module.exports = function(context, req) {
    context.res = {
        body: { name: "Azure Functions" }
    };
    context.done();
};

This will return an application/json response.

If instead you have your data in a json string, you can have:

module.exports = function(context, req) {
    context.res = {
        body: '{ "name": "Azure Functions" }'
    };

    context.done();
};

Which will return an application/json response because it sniffs that it is valid json.

David Ebbo
  • 42,443
  • 8
  • 103
  • 117
  • Does this always work, meaning is the req and res always implicitly available and it will always make best guess about content types for output request objects? Or, is it only implied when your function is triggered by HTTP request? It was my understanding that only when function is triggered by http request does it implicitly add the request (input) and response (output) bindings. If it was any other tigger type I would need to manually add the response output binding and it also would not implicitly know to add content headers? – Matt Mazzola Aug 25 '16 at 06:34
  • Only for http requests is there any req/res. For other trigger types like queue, they are triggered internally - there is no request/response. – mathewc Aug 25 '16 at 18:11
  • I understood how azure functions return Json responses. I am having the authorisation level to be anonymous. when I invoke an http call, I receive a proper response in postman, but I could not receive when I use it in my react app. on digging deeper, I found out, I receive the response but the response's body is an object of readable stream. How do i get my response body? Any idea ? @david – Lakshman Diwaakar Oct 03 '16 at 03:26
  • 1
    @LakshmanDiwaakar that sounds like a distinct question. Can you start a new one with more details about what you're doing? Or open issue on https://github.com/Azure/azure-webjobs-sdk-script – David Ebbo Oct 03 '16 at 20:23
  • @david I have posted as a separate question. Awaiting for your answer. http://stackoverflow.com/questions/39842944/decoding-the-response-body-from-azure-functions – Lakshman Diwaakar Oct 04 '16 at 01:41
  • @DavidEbbo I am tried this out on 11/25/2017 and `headers` needs to be specified to return JSON as @spooky answered in https://stackoverflow.com/a/42963573/4035 – dance2die Nov 25 '17 at 18:52
  • This works for me, you can add headers: { 'Content-Type': 'application/json' } for json response – Álvaro Agüero Mar 27 '20 at 21:11
2
module.exports = function (context, req) {
context.log('JavaScript HTTP trigger function processed a request.');

if (req.query.name || (req.body && req.body.name)) {
    context.res = {
        // status: 200, /* Defaults to 200 */
        body: {"data":"Hello"},
        headers: {
            'Content-Type': 'application/json'
        }
    };
}
else {
    // res = {
    //     status: 400,
    //     body: "Please pass a name on the query string or in the request body"
    // };
}
context.done(null,res);
1

I would like to add one more point. Apart from making the body: a JSON object, the request should also contain proper headers telling server what content type we are interested in. I could see that same Azure function when just invoked via browser using URL gives XML response, but when invoking from script or tools like Postman it gives JSON.

Community
  • 1
  • 1
Joy George Kunjikkuru
  • 1,495
  • 13
  • 27
1

I feel like the answer has been given but it hasn't been clearly presented so I thought I'd answer as well in case it will help anyone coming behind me. I too have created a function that most definitely returns a Javascript object but if I copy and paste the URL in the Azure Function UI and just open a new tab in Chrome and try to view the output, I actually get back an XML document that tells me there's an error (not surprising there's an error as many characters in the Javascript would have blown up the XML). So, as others have mentioned, the key is sending the appropriate headers with your request. When you copy/paste the URL into your browser, the browser is sending a request header that looks similar to this:

text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,/;q=0.8

When that happens, you see the XML return as described in this link: https://github.com/strongloop/strong-remoting/issues/118

In order to get around this problem and see what the data would look like with a JSON request, either use a utility like Postman: https://chrome.google.com/webstore/detail/postman/fhbjgbiflinjbdggehcddcbncdddomop?hl=en

Accept: application/json

Sample Postman Header Settings

Or use a CURL command and pass in the proper Accept header.

As you can see in the screenshot above, when I provided the proper header, I get back the JSON response I would expect.

Allen Underwood
  • 517
  • 5
  • 11
0

You can also use JSON.stringify() to make a valid json string out of your js-object:

jsonData = { value: "test" }:

context.res = {
   body: JSON.stringify(jsonData)
};
David Leitner
  • 3,312
  • 1
  • 18
  • 27