dukable
dukable

Reputation: 4058

Proper way to set response status and JSON content in a REST API made with nodejs and express

I am playing around with Nodejs and express by building a small rest API. My question is, what is the good practice/best way to set the code status, as well as the response data?

Let me explain with a little bit of code (I will not put the node and express code necessary to start the server, just the router methods that are concerned):

router.get('/users/:id', function(req, res, next) {
  var user = users.getUserById(req.params.id);
  res.json(user);
});


exports.getUserById = function(id) {
  for (var i = 0; i < users.length; i++) {
    if (users[i].id == id) return users[i];
  }
};

The code below works perfectly, and when sending a request with Postman, I get the following result: enter image description here

As you can see, the status shows 200, which is OK. But is this the best way to do this? Is there a case where I should have to set the status myself, as well as the returned JSON? Or is that always handled by express?

For example, I just made a quick test and slightly modified the get method above:

router.get('/users/:id', function(req, res, next) {
  var user = users.getUserById(req.params.id);
  if (user == null || user == 'undefined') {
    res.status(404);
  }
  res.json(user);
});

As you can see, if the user is not found in the array, I will just set a status of 404.

Resources/advices to learn more about this topic are more than welcome.

Upvotes: 235

Views: 363949

Answers (14)

Kunal goswami
Kunal goswami

Reputation: 69

Best way to write standard code for Node API CRUD operations

Create a handler which return success and fail case, it can be customised as per requirement

    const responseUpdate = (status, response = null, message = "") => {
    if (status == 200) {
        return {
            status: 200,
            data: response,
            message: "Success"
          };
    } else {
        return {
            status: 500,
            message: message
          };
    }
};

then in controller use your handler

const createCompany= async (req, res) => {
    try {
        const company = await Company.create(req.body);
        res.status(200).json(responseUpdate(200, company));
    } catch (error) {
        res.status(500).json(responseUpdate(500, null, error.message));
    }
};

Upvotes: 0

WasiF
WasiF

Reputation: 28939

The standard way to get full HttpResponse that includes following properties

  1. body //contains your data
  2. headers
  3. ok
  4. status
  5. statusText
  6. type
  7. url

On backend, do this

router.post('/signup', (req, res, next) => {
    // res object have its own statusMessage property so utilize this
    res.statusText = 'You have signed-up succesfully'
    return res.status(200).send('You are doing a great job')
})

On Frontend e.g. in Angular, just do:

let url = `http://example.com/signup`
this.http.post(url, { profile: data }, {
    observe: 'response' // remember to add this, you'll get pure HttpResponse
}).subscribe(response => {
    console.log(response)
})

Upvotes: 8

yuranos
yuranos

Reputation: 9725

I don't see anyone mentioned the fact that the order of method calls on res object is important. I'm new to nodejs and didn't realize at first that res.json() does more than just setting the body of the response. It actually tries to infer the response status as well. So, if done like so:

res.json({"message": "Bad parameters"})
res.status(400)

The second line would be of no use, because based on the correctly built json express/nodejs will already infer the success status(200).

Upvotes: 0

Hanzla Habib
Hanzla Habib

Reputation: 3723

res.sendStatus(status) has been added as of version 4.9.0

you can use one of these res.sendStatus() || res.status() methods

below is difference in between res.sendStatus() || res.status()


res.sendStatus(200) // equivalent to res.status(200).send('OK')
res.sendStatus(403) // equivalent to res.status(403).send('Forbidden')
res.sendStatus(404) // equivalent to res.status(404).send('Not Found')
res.sendStatus(500) // equivalent to res.status(500).send('Internal Server Error')

I hope someone finds this helpful thanks

Upvotes: 1

Kade
Kade

Reputation: 1032

FOR IIS

If you are using iisnode to run nodejs through IIS, keep in mind that IIS by default replaces any error message you send.

This means that if you send res.status(401).json({message: "Incorrect authorization token"}) You would get back You do not have permission to view this directory or page.

This behavior can be turned off by using adding the following code to your web.config file under <system.webServer> (source):

<httpErrors existingResponse="PassThrough" />

Upvotes: 2

Radu
Radu

Reputation: 524

The best way of sending an error response would be return res.status(400).send({ message: 'An error has occurred' }).

Then, in your frontend you can catch it using something like this:

        url: your_url,
        method: 'POST',
        headers: headers,
        data: JSON.stringify(body),
    })
        .then((res) => {
            console.log('success', res);
        })
        .catch((err) => {
            err.response && err.response.data && this.setState({ apiResponse: err.response.data })
        })

Just logging err won't work, as your sent message object resides in err.response.data.

Hope that helps!

Upvotes: 3

Prathamesh More
Prathamesh More

Reputation: 1489

You could do this

            return res.status(201).json({
                statusCode: req.statusCode,
                method: req.method,
                message: 'Question has been added'
            });

Upvotes: 2

Sma Ma
Sma Ma

Reputation: 3725

try {
  var data = {foo: "bar"};
  res.json(JSON.stringify(data));
}
catch (e) {
  res.status(500).json(JSON.stringify(e));
}

Upvotes: 4

Michał Dudak
Michał Dudak

Reputation: 5048

Express API reference covers this case.

See status and send.

In short, you just have to call the status method before calling json or send:

res.status(500).send({ error: "boo:(" });

Upvotes: 294

cmlndz
cmlndz

Reputation: 2387

A list of HTTP Status Codes

The good-practice regarding status response is to, predictably, send the proper HTTP status code depending on the error (4xx for client errors, 5xx for server errors), regarding the actual JSON response there's no "bible" but a good idea could be to send (again) the status and data as 2 different properties of the root object in a successful response (this way you are giving the client the chance to capture the status from the HTTP headers and the payload itself) and a 3rd property explaining the error in a human-understandable way in the case of an error.

Stripe's API behaves similarly in the real world.

i.e.

OK

200, {status: 200, data: [...]}

Error

400, {status: 400, data: null, message: "You must send foo and bar to baz..."}

Upvotes: 29

mzalazar
mzalazar

Reputation: 6606

You could do it this way:

res.status(400).json(json_response);

This will set the HTTP status code to 400, it works even in express 4.

Upvotes: 87

mrks
mrks

Reputation: 5631

I am using this in my Express.js application:

app.get('/', function (req, res) {
    res.status(200).json({
        message: 'Welcome to the project-name api'
    });
});

Upvotes: 14

Gustavo Grisales
Gustavo Grisales

Reputation: 53

res.status(500).jsonp(dataRes);

Upvotes: 4

Jordonias
Jordonias

Reputation: 5848

status of 200 will be the default when using res.send, res.json, etc.

You can set the status like res.status(500).json({ error: 'something is wrong' });

Often I'll do something like...

router.get('/something', function(req, res, next) {
  // Some stuff here
  if(err) {
    res.status(500);
    return next(err);
  }
  // More stuff here
});

Then have my error middleware send the response, and do anything else I need to do when there is an error.

Additionally: res.sendStatus(status) has been added as of version 4.9.0 http://expressjs.com/4x/api.html#res.sendStatus

Upvotes: 47

Related Questions