Co powinien zawierać "dobry" Error Response?

Jak Waszym zdaniem powinien wyglądać dobry JSON z komunikatem błędu?

Czy np.:

render status: 401, json: {error: "jakiś komunikat"}

czy tez może

render status: 401, json: {code: 401, error: "jakiś komunikat"}

?
Czy dobrą praktyką (i pomysłem) jest wstawianie code: również do wnętrza JSON’a?

Nie, wystarczy w statusie. Wtedy w kliencie odczytujesz go bezpośrednio z odpowiedzi, a nie z jej ciała.

W statusie też przekazuję.
Bardziej interesuje mnie, czy taka dodatkowa informacja w body ma sens, czy to się może komuś przydać, czy stanowi jednak niepotrzebny “szum informacyjny” :wink:

Z Twojej wypowiedzi wnioskuję, że to “szum”.
Inni też mają takie zdanie?

Ja zdecydowanie tak. Po co duplikować to info w body, skoro i tak leci (i musi lecieć) w statusie?

OK, dzięki za Wasze rady. :slight_smile:

Odpowiedź nie jest taka prosta, są różne podejścia, niektórzy np daja HTTP code 200 i w json error: 422 np … polecam poczytac API twittera, Facebooka i innych, są materiały na sieci (https://geemus.gitbooks.io/http-api-design/content/responses/generate-structured-errors.html) np polecam. Masz tez JSON-API (http://jsonapi.org/format/#error-objects)powoli standard, Hypermedia API … nie ma prostej odpowiedzi

Dzięki za te wszystkie rady, linki i sugestie.

Na marginesie tego, co napisał @gotar oraz tego, co było genezą mojego pytania, to dodam, że wybierając: http://editor.swagger.io/ też w przykładach błędy są opisane jako:

ErrorModel {
  code: integer *
  message: string *
}

Lub w innym przykładzie

ErrorModel {
  code: integer *
  message: string *
  fields: string *
}

idz w json-api ktos inny madry to przemyslal ;]

przydaje sie url (jesli to api i hypermedia i link do dokumentacji, code, message, … wszystko jest opisane tam)

trzeba pamietac ze po co sa te komunikaty, przeciez nie dla nas, tylko dla uzytkownikow tego API. Wiec jak blad im wystapi powinien byc dosc dokladny by nie musieli sie zastanawiac sie co teraz i czemu. Link do dokumentacji, grupa bledu, code jego, … to wszystko pomaga uzytkownikowi a nam daje spokoj, bo nie trzeba odpowiadac na szereg pytan, na ktore moga znalezc odpowiedz w dokumentacji

Jak dla mnie porzadnie zaprojektowana wiadomosc bledu jest bardzo istotna to z nia zostanie uzytkownik w czasie problemu

Jako programista, który miałby korzystać z takich komunikatów, to też bym wolał mieć błąd opisany najszerzej jak to możliwe. Niemniej jednak warto chyba w swojej aplikacji starać się zunifikować choćby komunikaty o błędach. :wink:

Jeżeli przykładowo mam Devisa, który wysyła
{"error": "Invalid login or password."} ,
to trochę słabo będzie wyglądało, gdy API w innej części (tej oprogramowanej przeze mnie) będzie zwracało inny format np:

{code: "not_found", message: "No record found for params[:name] = 'Zulu Gula' "}

… Tak jak napisałeś wcześniej - temat nie jest taki prosty.

HTTP status is mandatory as API should follow RESTful conventions. But body with textual description should also be presented. It’s makes life easier for clients of your API while debugging it.
But also I recommend using additional custom error code which can expand HTTP status code.
E.g 422 unprocessable entity.
And custom codes can be like 422001, 422002 etc
Then in your API documentation describe each code meaning.
E.g 422001 invalid user name, 422002 wrong company size.
Let me explain why this can be useful. Sometimes API clients would like to show their own error message to their users. Maybe in a different language. Without custom error code they are forced to show the same error message as received in API response. Otherwise they should somehow parse body of API responses to march them own defined messages.

HTTP/1.1 422 Unprocessable Entity
Content-Type: application/hardparty.api+json

{
  "errors": [
    {
      "code": "422261"
      "detail": "User email should contain @ symbol"
    }
  ]
}
1 Like

No dobrze, w takim wypadku pytanie dotyczyło czegoś zupełnie innego, bo pytałeś o duplikację błędu a nie jego precyzowanie. Wiadomym jest, że każdy błąd powinien być maksymalnie precyzyjny i do tego powinno API dążyć w odpowiedziach na requesty. Świetny przykład w odpowiedzi od @roleme.

Ale nie zawsze się da coś doprecyzować.
Jeżeli mam coś takiego:

render status: :not_found,
         json: { error: "Brak rekordów dla '#{params[:pesel]}')" }

to doprecyzować będzie to trudno, a przecież chcąc zachować spójny format powinniśmy napisać:

render status: :not_found,
         json: { code: 404,
                error: "Brak rekordów dla '#{params[:pesel]}')" }

… i stąd moje początkowe pytanie, czy to dobry pomysł, by takie kody umieszczać w body.
@gotar w zasadzie doskonale wyjaśnił mi, skąd się to wzięło. Teraz tylko pytanie, czy to aplikować w swojej apce?

Wydaje mi się, że korzystając z takiego Devise oraz samemu pisząc w stylu zaprezentowanym przez @roleme to skazani jesteśmy na prezentowanie komunikatów w sposób zróżnicowany, tj raz z code: wewnątrz, a raz nie. Nie do końca mi się to podoba, ale chyba nie ma innego wyjścia.
Podobnie będzie przecież zawsze, gdy będziemy mieli w aplikacji fragmenty montowane od “innych dostawców”. Przecież nie mamy wpływu na to jak oni opisali zwracany błąd.

Jeśli piszemy API to Kod błędu powinien być zawsze i powtarzać kod HTTP. Nie wszędzie i zawsze łatwo odczytać dane z nagłówka. Tutaj przekazując go w treści ułatwiamy innym prace i od razu przekazujemy wszystkie wiadomości. To ze w naszych narzędziach, ekosystemie mamy łatwy dostęp do nagłówków nie znaczy ze np ktoś kto korzystając z naszego api i pisząc apke na iOS bedzie myśl tak samo.

Błąd zwracany przez systemy których używamy powinnismy opakować swoim błędem. Każdy błąd powinien być opisany w dokumentacji. Ogólnie jest masa materiałów w sieci jak to dobrze robić.

Ale to oznacza sporo dodatkowej pracy. Np te błędy Devise będziemy musieli przechwytywać, by je opakować. To trochę utrudnia życie.
Nawet w doskonałej (moim zdaniem) prezentacji “APIs on Rails” jest przykład listing 3.10:

  def create
    user = User.new(user_params)
    if user.save
      render json: user, status: 201, location: [:api, user]
    else
      render json: { errors: user.errors }, status: 422
    end
  end

Czy zatem dużym błędem będzie zwracanie błędów własnego kodu w tym rozszerzonym formacie, a zwracanie innych (np z Devise) w stylu uproszczonym?

Jeśli kodujesz typowy rails way to jest to problem, jak ten kod “powinien wygladac” to za dużo by pisać w poście. Polecam traiblizer, blog Arkency, stamtąd do materiałów kolejnych.

Jeśli jesteś ciekaw jak pisać dobry kod. Zapraszam na konferencje wroclove.rb bedzie dużo dobrej wiedzy w jednym miejscu.

Jeszcze raz dzięki za te wszystkie rady i podpowiedzi.

Mówisz poważnie? Mam powtarzać headery w body, bo ktoś może nie umieć obsługiwać HTTP w swoim projekcie, jednocześnie chcąc korzystać z API po HTTP? Przecież to jakiś żart, jak może próbować parsować naszą odpowiedź, jeśli nie sprawdzi Content-Type odpowiedzi? Powtarzanie kodu HTTP w body to imo totalna bzdura, tak samo nie jestem fanem zwracania tajemniczych kodów jak “422261”, bo zmusza to do odwoływania się za każdym razem do dokumentacji. Moim zdaniem najlepiej jest zwrócić nie “gotowy string”, tylko klucz, jednoznacznie opisujący błąd oraz pozwalający dynamicznie tłumaczyć odpowiedzi, np.

{
  "errors": [
    {
      "phone_number": ["wrong_format", "too_short"],
      "email": ["taken"],
      "password": ["must_contain_uppercase_letter"]
    }
  ]
}

Nic nie każe. Mowię jak ja bym zrobił. Api nie piszemy dla siebie a dla innych, jeśli są 2 konkurencyjne i w momencie największej próby gdy oba rzuca błąd, jako użytkownik wybrał bym to które mi bardziej pomoże. Jako ze nie chce by użytkownik (klient) zdecydował sie na usługi konkurencji, staram sie by był zadowolony.

Problem nie jest duży, przechwytywanie wyjątków, błędów. Dekorator na nie … Ogólnie pomiędzy pisaniem kodu po prostu a dobrze jest wiele małych czynników. Trzeba by książkę a nie wiadomość pisać. I inni juz to zrobili. Typowy rails way ma swoje miejsce, ale nie jest to cel, czy silver bullet, a zazwyczaj szybki prototyp który pózniej trzeba mądrze urządzić.

Pojawiło sie w wątku wiele materiałów, zdań nie na co tu dłużej pisać. Każdy sam decyduje jak koduje, nie ma idealnego sposobu. Są tylko ścieżki, rzeczy które sie sprawdziły lub nie i które pasują do rożnych typów projektów i ich rozmiaru/skomplikowania.

Trochę juz w życiu projektów napisałem i jedyne co moge sie podzielić wiedza co sie sprawdziło a co nie.