REST API hata yanıt modeli ve hata kodları sistemi oluşturmanın en iyi yolu nedir?


15

Benim REST uygulaması sonraki yapı ile JSON hataları döndürür:

{
 "http_response":400,
 "dev_message":"There is a problem",
 "message_for_user":"Bad request",
 "some_internal_error_code":12345
}

Özellikler (dev_message, message_for_user, some_internal_error_code) için gerekli değerleri iletebileceğim ve bunları döndürebileceğim özel yanıt modeli oluşturmanızı öneririm. Kodda buna benzer:

$responseModel = new MyResponseModel(400,"Something is bad", etc...);

Bu model nasıl görünmeli? Sadece metin bilgilerini ileteceğim ve kod orada varsayılan 200 olacak şekilde successResponse () gibi yöntemler uygulamak gerekir? Buna takılıp kaldım. Ve bu sorumun ilk kısmı: Bu modeli uygulamam gerekiyor mu, bu iyi bir uygulama mı? Çünkü şimdilik sadece dizileri doğrudan koddan döndürüyorum.

İkinci bölüm hata kodu sistemi ile ilgilidir. Hata kodları belgelerde açıklanacaktır. Ama karşılaştığım sorun kodda. Hata kodlarını yönetmenin en iyi yolu nedir? Bunları modelin içine yazmalı mıyım? Yoksa bununla başa çıkmak için ayrı bir hizmet oluşturmak daha mı iyi olur?

GÜNCELLEME 1

Yanıt için model sınıfı uyguladım. Bu benzer Greg'in yanıtı, aynı mantık, ama ek olarak modelde kodlanmış yazılı hatalar var ve işte böyle görünüyor:

    class ErrorResponse
    {
     const SOME_ENTITY_NOT_FOUND = 100;
     protected $errorMessages = [100 => ["error_message" => "That entity doesn't exist!"]];

     ...some code...
    }

Bunu neden yaptım? Ne için?

  1. Kodda havalı görünüyor: return new ErrorResponse(ErrorResponse::SOME_ENTITY_NOT_FOUND );
  2. Kolay değiştirilebilir hata mesajı. Tüm iletiler denetleyici / hizmet / vb yerine ya da yerleştirdiğiniz her şey yerine tek bir yerde bulunur.

Bunu geliştirmek için herhangi bir öneriniz varsa, lütfen yorum yapın.

Yanıtlar:


13

Bu durumda, her zaman önce arayüzü düşünüyorum, sonra desteklemek için PHP kodu yazıyorum.

  1. Bu bir REST API'sıdır, bu nedenle anlamlı HTTP durum kodları bir zorunluluktur.
  2. İstemciye ve istemciden tutarlı, esnek veri yapıları gönderilmesini istiyorsunuz.

Yanlış gidebilecek her şeyi ve HTTP durum kodlarını düşünelim:

  • Sunucu bir hata veriyor (500)
  • Kimlik doğrulama hatası (401)
  • İstenen kaynak bulunamadı (404)
  • Değiştirdiğiniz veriler yüklendikten sonra değiştirildi (409)
  • Veri kaydedilirken doğrulama hataları (422)
  • Müşteri talep oranını aştı (429)
  • Desteklenmeyen dosya türü (415)

Daha sonra araştırabileceğiniz başka şeyler de var.

Hata durumlarının çoğu için, döndürülecek yalnızca bir hata mesajı vardır. 422 Unprocessable EntityBen "Doğrulama hataları" için kullandım tepki birden fazla hata --- form alanına başına bir veya daha fazla hata geri dönebilirler.

Hata yanıtları için esnek bir veri yapısına ihtiyacımız var.

Örnek olarak şunu ele alalım 500 Internal Server Error:

HTTP/1.1 500 Internal Server Error
Content-Type: text/json
Date: Fri, 16 Jan 2015 17:44:25 GMT
... other headers omitted ...

{
    "errors": {
        "general": [
            "Something went catastrophically wrong on the server! BWOOP! BWOOP! BWOOP!"
        ]
    }
}

Sunucuya bir şey POST göndermeye çalışırken basit doğrulama hataları ile kontrast:

HTTP/1.1 422 Unprocessable Entity
Content-Type: text/json
Date: Fri, 16 Jan 2015 17:44:25 GMT
... other headers omitted ...

{
    "errors": {
        "first_name": [
            "is required"
        ],
        "telephone": [
            "should not exceed 12 characters",
            "is not in the correct format"
        ]
    }
}

Burada önemli olan içerik türü text/json. Bu, istemci uygulamalarına yanıt gövdesini bir JSON kod çözücü ile deşifre edebileceklerini bildirir. Örneğin, dahili bir sunucu hatası yakalanmazsa ve genel "Bir şeyler ters gitti" web sayfanız yayınlanmazsa, içerik türü, text/html; charset=utf-8istemci uygulamalarının yanıt gövdesini JSON olarak kodlamayı denememesi için olmalıdır .

Bu, JSONP yanıtlarını desteklemeniz gerekene kadar tüm bul ve züppe görünüyor . 200 OKHatalar için bile bir yanıt vermelisiniz . Bu durumda, istemcinin bir JSONP yanıtı istediğini (genellikle adlı bir URL isteği parametresini algılayarak) tespit etmeniz callbackve veri yapısını biraz değiştirmeniz gerekir:

(GET / posts / 123? Callback = displayBlogPost)

<script type="text/javascript" src="/posts/123?callback=displayBlogPost"></script>

HTTP/1.1 200 OK
Content-Type: text/javascript
Date: Fri, 16 Jan 2015 17:44:25 GMT
... other headers omitted ...

displayBlogPost({
    "status": 500,
    "data": {
        "errors": {
            "general": [
                "Something went catastrophically wrong on the server! BWOOP! BWOOP! BWOOP!"
            ]
        }
    }
});

Daha sonra istemcideki yanıt işleyicisinin (bir web tarayıcısında), displayBlogPosttek bir argümanı kabul eden global bir JavaScript işlevi olmalıdır . Bu işlev, yanıtın başarılı olup olmadığını belirlemek zorunda kalır:

function displayBlogPost(response) {
    if (response.status == 500) {
        alert(response.data.errors.general[0]);
    }
}

Bu yüzden müşteriye baktık. Şimdi sunucuya bakalım.

<?php

class ResponseError
{
    const STATUS_INTERNAL_SERVER_ERROR = 500;
    const STATUS_UNPROCESSABLE_ENTITY = 422;

    private $status;
    private $messages;

    public function ResponseError($status, $message = null)
    {
        $this->status = $status;

        if (isset($message)) {
            $this->messages = array(
                'general' => array($message)
            );
        } else {
            $this->messages = array();
        }
    }

    public function addMessage($key, $message)
    {
        if (!isset($message)) {
            $message = $key;
            $key = 'general';
        }

        if (!isset($this->messages[$key])) {
            $this->messages[$key] = array();
        }

        $this->messages[$key][] = $message;
    }

    public function getMessages()
    {
        return $this->messages;
    }

    public function getStatus()
    {
        return $this->status;
    }
}

Ve bunu bir sunucu hatası durumunda kullanmak için:

try {
    // some code that throws an exception
}
catch (Exception $ex) {
    return new ResponseError(ResponseError::STATUS_INTERNAL_SERVER_ERROR, $ex->message);
}

Veya kullanıcı girişini doğrularken:

// Validate some input from the user, and it is invalid:

$response = new ResponseError(ResponseError::STATUS_UNPROCESSABLE_ENTITY);
$response->addMessage('first_name', 'is required');
$response->addMessage('telephone', 'should not exceed 12 characters');
$response->addMessage('telephone', 'is not in the correct format');

return $response;

Bundan sonra, yalnızca döndürülen yanıt nesnesini alıp JSON'a dönüştüren ve yanıtı neşeli yoluna gönderen bir şeye ihtiyacınız vardır.


Cevabınız için teşekkürler! Benzer bir çözüm uyguladım. Kendi başıma herhangi bir mesaj atmadığım tek fark, zaten ayarlanmış (güncellenmiş soruma bakın).
Grokking

-2

Benzer bir şeyle karşı karşıyaydım, 3 şey yaptım,

  1. ABCException adlı bir ExceptionHandler oluşturdum.

Java & Spring kullandığım için,

Olarak tanımladım

 public class ABCException extends Exception {
private String errorMessage;
private HttpStatus statusCode;

    public ABCException(String errorMessage,HttpStatus statusCode){
            super(errorMessage);
            this.statusCode = statusCode;

        }
    }

Sonra gerekli olan her yerde denir, böyle,

throw new ABCException("Invalid User",HttpStatus.CONFLICT);

Ve evet REST tabanlı web servisini kullanıyorsanız kontrol cihazınızda bir ExceptionHandler yapmanız gerekir.

@ExceptionHandlerSpring kullanıyorsanız açıklama ekleyin


Programcılar olduğu konusunda kavramsal soruları ve cevapları edilir beklenen açıklamak şeyler . Açıklama yerine kod dökümlerini atmak kodu IDE'den beyaz tahtaya kopyalamak gibidir: tanıdık gelebilir ve hatta bazen anlaşılabilir olabilir, ancak garip hissediyor ... sadece garip. Beyaz Tahta Derleyici Yok
Gnat
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.