Forma correcta de establecer el estado de respuesta y el contenido JSON en una API REST hecha con nodejs y express

187

Estoy jugando con Nodejs y expreso construyendo una pequeña API de descanso. Mi pregunta es, ¿cuál es la mejor práctica / mejor manera de configurar el estado del código, así como los datos de respuesta?

Permítanme explicarlo con un poco de código (no pondré el nodo y el código expreso necesario para iniciar el servidor, solo los métodos de enrutador que conciernen):

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];
  }
};

El siguiente código funciona perfectamente, y cuando envío una solicitud con Postman, obtengo el siguiente resultado: ingrese la descripción de la imagen aquí

Como puede ver, el estado muestra 200, que está bien. ¿Pero es esta la mejor manera de hacer esto? ¿Hay algún caso en el que deba establecer el estado yo mismo, así como el JSON devuelto? ¿O es eso siempre manejado por expreso?

Por ejemplo, acabo de hacer una prueba rápida y modifiqué ligeramente el método get anterior:

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);
});

Como puede ver, si el usuario no se encuentra en la matriz, solo estableceré un estado de 404.

Los recursos / consejos para aprender más sobre este tema son más que bienvenidos.

dukable
fuente
3
Esta es mi respuesta mejor calificada y no se acepta :( @dukable, sé que ha pasado un tiempo, pero ¿resolvió su problema?
Michał Dudak
@ MichałDudak: Sí, su respuesta debe ser la aceptada. Pero este usuario dukable no está activo desde el 15 de octubre de 2015 (como el 31 de julio de 2017). +1 para su respuesta de todos modos;)
Amol M Kulkarni

Respuestas:

230

La referencia Express API cubre este caso.

Ver estado y enviar .

En resumen, solo tiene que llamar al statusmétodo antes de llamar jsono send:

res.status(500).send({ error: "boo:(" });
Michał Dudak
fuente
32
Si solo desea enviar un código de estado (sin datos), el método seríares.sendStatus(400);
internet-nico
3
Esto ya no parece funcionar. La respuesta se envía con el código de estado correcto, pero sin cuerpo ...
LondonRob
2
Ignora mi último comentario. Si establece el estado en 204 (Sin contenido), no envía el cuerpo.
LondonRob
2
@ internet-nico también res.sendStatus(400);envía una cadena de datos, es equivalente ares.status(400).send('Not Found')
Davide
74

Podrías hacerlo de esta manera:

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

Esto establecerá el código de estado HTTP en 400, funciona incluso en express 4.

mzalazar
fuente
17
express deprecated res.json(status, obj): Use res.status(status).json(obj) instead Entonces, res.status(400).json(json_response)sería preciso hoy en día.
Will Luce
Sí, gracias ... está marcado como obsoleto, pero aún funciona: P Su comentario es válido, buen punto.
mzalazar
A favor de anwer -res.status(500).send({ error: "boo:(" });
prayagupd
41

estado 200 será el predeterminado cuando se utiliza res.send, res.jsonetc.

Puedes establecer el estado como res.status(500).json({ error: 'something is wrong' });

A menudo haré algo como ...

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

Luego, haga que mi middleware de error envíe la respuesta y haga cualquier otra cosa que deba hacer cuando haya un error.

Además: res.sendStatus(status)se ha agregado a partir de la versión 4.9.0 http://expressjs.com/4x/api.html#res.sendStatus

Jordonias
fuente
23

Una lista de códigos de estado HTTP

La buena práctica con respecto a la respuesta de estado es, previsiblemente, enviar el código de estado HTTP adecuado dependiendo del error (4xx para errores del cliente, 5xx para errores del servidor), con respecto a la respuesta JSON real no hay "biblia", pero una buena idea podría ser para enviar (nuevamente) el estado y los datos como 2 propiedades diferentes del objeto raíz en una respuesta exitosa (de esta manera le está dando al cliente la oportunidad de capturar el estado de los encabezados HTTP y la carga útil en sí) y una tercera propiedad que explica el error de una manera comprensible para el ser humano en el caso de un error.

La API de Stripe se comporta de manera similar en el mundo real.

es decir

Okay

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

Error

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

Estoy usando esto en mi aplicación Express.js:

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

La forma estándar de obtener HttpResponse completo que incluye las siguientes propiedades

  1. cuerpo // contiene sus datos
  2. encabezados
  3. Okay
  4. estado
  5. statusText
  6. tipo
  7. url

En el backend , haz esto

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

En Frontend, por ejemplo Angular, en , solo haz:

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)
})
WasiF
fuente
3
res.status(500).jsonp(dataRes);
Gustavo Grisales
fuente
2
try {
  var data = {foo: "bar"};
  res.json(JSON.stringify(data));
}
catch (e) {
  res.status(500).json(JSON.stringify(e));
}
Sma Ma
fuente
0

Podrías hacer esto

            return res.status(201).json({
                statusCode: req.statusCode,
                method: req.method,
                message: 'Question has been added'
            });
Prathamesh Más
fuente
0

La mejor manera de enviar una respuesta de error sería return res.status(400).send({ message: 'An error has occurred' }).

Luego, en tu interfaz puedes atraparlo usando algo como esto:

        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 })
        })

Simplemente el inicio de sesión errno funcionará, ya que su objeto de mensaje enviado reside err.response.data.

¡Espero que ayude!

Radu
fuente