Właściwy sposób ustawiania statusu odpowiedzi i treści JSON w interfejsie API REST wykonanym za pomocą nodejs i express

186

Bawię się z Nodejsem i wyrażam, budując API małego odpoczynku. Moje pytanie brzmi: jaka jest dobra praktyka / najlepszy sposób na ustawienie statusu kodu, a także danych odpowiedzi?

Pozwól, że wyjaśnię trochę kodu (nie umieszczę węzła i kodu ekspresowego niezbędnego do uruchomienia serwera, tylko metody routera, których to dotyczy):

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

Poniższy kod działa idealnie, a wysyłając zapytanie za pomocą Postmana, otrzymuję następujący wynik: wprowadź opis zdjęcia tutaj

Jak widać, status pokazuje 200, co jest OK. Ale czy to najlepszy sposób, aby to zrobić? Czy istnieje przypadek, w którym powinienem sam ustawić status, a także zwrócony JSON? Czy zawsze jest to obsługiwane przez ekspres?

Na przykład właśnie wykonałem szybki test i nieznacznie zmodyfikowałem powyższą metodę get:

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

Jak widać, jeśli użytkownika nie ma w tablicy, ustawię tylko status 404.

Zasoby / porady, aby dowiedzieć się więcej na ten temat, są mile widziane.

dukable
źródło
3
To jest moja najwyżej oceniana odpowiedź i nie została zaakceptowana :( @dukable, wiem, że minęło trochę czasu, ale czy to rozwiązało Twój problem?
Michał Dudak
@ MichałDudak: Tak, twoja odpowiedź powinna być zaakceptowana. Ale ten sprawdzalny użytkownik nie jest aktywny od 15 października 2015 r. (Stan na 31 lipca 2017 r.). W każdym razie +1 za odpowiedź;)
Amol M. Kulkarni

Odpowiedzi:

230

Dokumentacja Express API dotyczy tej sprawy.

Zobacz status i wyślij .

Krótko mówiąc, wystarczy wywołać statusmetodę przed wywołaniem jsonlub send:

res.status(500).send({ error: "boo:(" });
Michał Dudak
źródło
32
Jeśli chcesz tylko wysłać kod stanu (bez danych), metodą może byćres.sendStatus(400);
internet-nico
3
To już nie działa. Odpowiedź jest wysyłana z poprawnym kodem statusu, ale bez treści ....
LondonRob
2
Zignoruj ​​mój ostatni komentarz. Jeśli ustawisz status na 204 (Brak treści), nie wyśle ​​ono treści.
LondonRob
2
@ internet-nico również res.sendStatus(400);przesyła ciąg danych, jest to odpowiednikres.status(400).send('Not Found')
Davide
74

Możesz to zrobić w ten sposób:

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

Spowoduje to ustawienie kodu statusu HTTP na 400, działa nawet w trybie ekspresowym 4.

mzalazar
źródło
17
express deprecated res.json(status, obj): Use res.status(status).json(obj) instead W res.status(400).json(json_response)dzisiejszych czasach byłoby to trafne.
Will Luce,
Tak, dziękuję ... jest oznaczony jako przestarzały, ale nadal działa: P Twój komentarz jest prawidłowy, dobra uwaga.
mzalazar
41

status 200 będzie domyślnym podczas korzystania res.send, res.jsonitp

Możesz ustawić status jak res.status(500).json({ error: 'something is wrong' });

Często zrobię coś takiego ...

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

Następnie niech moje oprogramowanie pośredniczące z błędem wyśle ​​odpowiedź i zrobi wszystko, co muszę zrobić, gdy wystąpi błąd.

Dodatkowo: res.sendStatus(status)został dodany od wersji 4.9.0 http://expressjs.com/4x/api.html#res.sendStatus

Jordonias
źródło
23

Lista kodów stanu HTTP

Dobrą praktyką dotyczącą odpowiedzi statusu jest, jak można przewidzieć, wysyłanie odpowiedniego kodu statusu HTTP w zależności od błędu (4xx dla błędów klienta, 5xx dla błędów serwera), w odniesieniu do faktycznej odpowiedzi JSON nie ma „biblii”, ale dobrym pomysłem może być wysłać (ponownie) status i dane jako 2 różne właściwości obiektu głównego w udanej odpowiedzi (w ten sposób dajesz klientowi szansę na przechwycenie statusu z nagłówków HTTP i samego ładunku) oraz trzecią właściwość wyjaśniającą błąd w sposób zrozumiały dla człowieka w przypadku błędu.

API Stripe zachowuje się podobnie w prawdziwym świecie.

to znaczy

dobrze

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

Błąd

400, {status: 400, data: null, message: "You must send foo and bar to baz..."}
cmlndz
źródło
13

Używam tego w mojej aplikacji Express.js:

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

Standardowy sposób uzyskania pełnej odpowiedzi HttpResponse, która obejmuje następujące właściwości

  1. body // zawiera twoje dane
  2. nagłówki
  3. dobrze
  4. status
  5. statusText
  6. rodzaj
  7. adres URL

Na backend to zrobić

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

Na Frontend np. W Angular, po prostu wykonaj:

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

Mógłbyś to zrobić

            return res.status(201).json({
                statusCode: req.statusCode,
                method: req.method,
                message: 'Question has been added'
            });
Prathamesh More
źródło
0

Najlepszym sposobem wysłania odpowiedzi na błąd byłoby return res.status(400).send({ message: 'An error has occurred' }).

Następnie w swoim interfejsie możesz go złapać, używając czegoś takiego:

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

Po prostu rejestrowanie errnie będzie działać, ponieważ obiekt wysłanej wiadomości znajduje się w nim err.response.data.

Mam nadzieję, że to pomaga!

Radu
źródło