Maneira correta de definir o status da resposta e o conteúdo JSON em uma API REST feita com nodejs e express

186

Estou brincando com o Nodejs e expresso criando uma pequena API de descanso. Minha pergunta é: qual é a melhor prática / melhor maneira de definir o status do código, bem como os dados de resposta?

Deixe-me explicar com um pouco de código (não colocarei o nó e o código expresso necessário para iniciar o servidor, apenas os métodos do roteador):

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

O código abaixo funciona perfeitamente e, ao enviar uma solicitação com o Postman, recebo o seguinte resultado: insira a descrição da imagem aqui

Como você pode ver, o status mostra 200, o que está OK. Mas essa é a melhor maneira de fazer isso? Existe um caso em que eu próprio precise definir o status, bem como o JSON retornado? Ou isso é sempre tratado por expresso?

Por exemplo, acabei de fazer um teste rápido e modifiquei levemente o método get acima:

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 você pode ver, se o usuário não for encontrado na matriz, apenas definirei o status 404.

Recursos / conselhos para aprender mais sobre este tópico são bem-vindos.

dukable
fonte
3
Este é o meu maior resposta nominal e não é aceito :( @dukable, eu sei que tem sido um tempo, mas tinha que resolver o seu problema?
Michał Dudak
@ MichałDudak: Sim, sua resposta deve ser a aceita. Mas esse usuário dukable não está ativo desde 15 de outubro de 2015 (como em 31 de julho de 2017). +1 de qualquer maneira;) #
Amol M Kulkarni

Respostas:

230

A referência da API Express cobre esse caso.

Veja o status e envie .

Em resumo, você só precisa chamar o statusmétodo antes de chamar jsonou send:

res.status(500).send({ error: "boo:(" });
Michał Dudak
fonte
32
Se você deseja enviar apenas um código de status (sem dados), o método seriares.sendStatus(400);
internet-nico
3
Isso parece não funcionar mais. A resposta é enviada com o código de status correto, mas nenhum corpo ....
LondonRob
2
Ignore meu último comentário. Se você definir o status como 204 (Sem conteúdo), ele não enviará o corpo.
LondonRob
2
@ internet-nico res.sendStatus(400);enviar um dados de cadeia também, é equivalente ares.status(400).send('Not Found')
Davide
74

Você poderia fazer assim:

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

Isso definirá o código de status HTTP para 400, ele funciona mesmo no express 4.

mzalazar
fonte
17
express deprecated res.json(status, obj): Use res.status(status).json(obj) instead Então, res.status(400).json(json_response)seria preciso hoje em dia.
Will Luce
Sim, obrigado ... está marcado como obsoleto, mas ainda funciona: P Seu comentário é válido, bom ponto.
Mzalazar
A favor de anwer - #res.status(500).send({ error: "boo:(" });
prayagupd
41

status do 200 será o padrão quando se utiliza res.send, res.jsonetc.

Você pode definir o status como res.status(500).json({ error: 'something is wrong' });

Muitas vezes eu vou fazer algo como ...

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

Depois, meu middleware de erro envia a resposta e faz qualquer outra coisa que preciso fazer quando há um erro.

Adicionalmente: res.sendStatus(status)foi adicionado na versão 4.9.0 http://expressjs.com/4x/api.html#res.sendStatus

Jordonias
fonte
23

Uma lista de códigos de status HTTP

A boa prática em relação à resposta de status é, previsivelmente, enviar o código de status HTTP adequado, dependendo do erro (4xx para erros do cliente, 5xx para erros do servidor), em relação à resposta JSON real, não há "bíblia", mas uma boa idéia pode ser para enviar (novamente) o status e os dados como duas propriedades diferentes do objeto raiz em uma resposta bem-sucedida (dessa forma, você está dando ao cliente a chance de capturar o status dos cabeçalhos HTTP e da própria carga útil) e uma terceira propriedade explicando o erro de uma maneira compreensível ao ser humano no caso de um erro.

A API do Stripe se comporta de maneira semelhante no mundo real.

ie

Está bem

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

Erro

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

Estou usando isso no meu aplicativo Express.js:

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

A maneira padrão de obter o HttpResponse completo que inclui as seguintes propriedades

  1. body // contém seus dados
  2. cabeçalhos
  3. Está bem
  4. status
  5. statusText
  6. tipo
  7. url

No back - end , faça isso

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

No Frontend, por exemplo Angular, faça:

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

Você poderia fazer isso

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

A melhor maneira de enviar uma resposta de erro seria return res.status(400).send({ message: 'An error has occurred' }).

Então, no seu front-end, você pode capturá-lo usando algo como isto:

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

Apenas o log errnão funcionará, pois o objeto da mensagem enviada reside err.response.data.

Espero que ajude!

Radu
fonte