Cách tốt nhất để tạo mô hình phản hồi lỗi REST API và hệ thống mã lỗi là gì?


15

Việc triển khai REST của tôi sẽ trả về các lỗi trong JSON với cấu trúc tiếp theo:

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

Tôi đề nghị tạo mô hình phản hồi đặc biệt, nơi tôi có thể chuyển các giá trị cần thiết cho các thuộc tính (dev_message, message_for_user, some_iternal_error_code) và trả về chúng. Trong mã nó sẽ tương tự như thế này:

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

Mô hình này nên như thế nào? Tôi có nên triển khai các phương thức hay không, ví dụ thành côngResponse () trong đó tôi sẽ chỉ truyền thông tin văn bản và mã sẽ được mặc định 200 ở đó? Tôi bị mắc kẹt với điều này. Và đây là phần đầu tiên trong câu hỏi của tôi: tôi có cần thực hiện mô hình này không, đây có phải là cách thực hành tốt không? Bởi vì bây giờ, tôi chỉ trả về mảng trực tiếp từ mã.

Phần thứ hai là về hệ thống mã lỗi. Mã lỗi sẽ được mô tả trong tài liệu. Nhưng vấn đề tôi gặp phải là ở mã. Cách tốt nhất để quản lý mã lỗi là gì? Tôi có nên viết chúng bên trong mô hình? Hoặc sẽ tốt hơn để tạo ra dịch vụ riêng biệt để xử lý việc này?

CẬP NHẬT 1

Tôi đã triển khai lớp mô hình để phản hồi. Đó là câu trả lời tương tự của Greg, logic tương tự, nhưng thêm vào đó tôi có lỗi viết mã cứng trong mô hình và đây là cách nó trông như sau:

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

     ...some code...
    }

Tại sao tôi làm điều này? Và để làm gì?

  1. Nó trông thật tuyệt trong mã: return new ErrorResponse(ErrorResponse::SOME_ENTITY_NOT_FOUND );
  2. Dễ dàng thay đổi thông báo lỗi. Tất cả các tin nhắn đều ở một nơi thay vì bộ điều khiển / dịch vụ / vv hoặc bất cứ điều gì bạn sẽ đặt nó.

Nếu bạn có bất kỳ đề xuất để cải thiện điều này, xin vui lòng, bình luận.

Câu trả lời:


13

Trong tình huống này, tôi luôn nghĩ đến giao diện trước, sau đó viết mã PHP để hỗ trợ nó.

  1. Đó là API REST, vì vậy các mã trạng thái HTTP có ý nghĩa là bắt buộc.
  2. Bạn muốn cấu trúc dữ liệu nhất quán, linh hoạt được gửi đến và từ máy khách.

Hãy nghĩ về tất cả những điều có thể sai và mã trạng thái HTTP của họ:

  • Máy chủ đưa ra lỗi (500)
  • Lỗi xác thực (401)
  • Không tìm thấy tài nguyên yêu cầu (404)
  • Dữ liệu bạn đang sửa đổi đã được thay đổi kể từ khi bạn tải nó (409)
  • Lỗi xác thực khi lưu dữ liệu (422)
  • Khách hàng đã vượt quá tỷ lệ yêu cầu của họ (429)
  • Loại tệp không được hỗ trợ (415)

Lưu ý, có những cái khác mà bạn có thể nghiên cứu sau này.

Đối với hầu hết các điều kiện thất bại, chỉ có một thông báo lỗi được trả về. Các 422 Unprocessable Entityphản ứng, mà tôi đã sử dụng cho "lỗi xác nhận" có thể trở lại nhiều hơn một lỗi --- Một hoặc nhiều lỗi mỗi lĩnh vực hình thức.

Chúng tôi cần một cấu trúc dữ liệu linh hoạt để phản hồi lỗi.

Hãy làm ví dụ, các 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!"
        ]
    }
}

Ngược lại với các lỗi xác nhận đơn giản khi cố gắng gửi một cái gì đó lên máy chủ:

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

Họ quan trọng ở đây là loại nội dung text/json. Điều này cho các ứng dụng khách biết rằng họ có thể giải mã phần thân phản hồi bằng bộ giải mã JSON. Nếu, giả sử, lỗi máy chủ nội bộ không bị phát hiện và trang web "Đã xảy ra lỗi" chung chung của bạn được phân phối thay thế, loại nội dung phải text/html; charset=utf-8để ứng dụng khách không cố giải mã nội dung phản hồi dưới dạng JSON.

Điều này có vẻ như tất cả đều được tìm thấy và cho đến khi bạn cần hỗ trợ các phản hồi JSONP . Bạn phải trả lại một 200 OKphản hồi, ngay cả đối với những thất bại. Trong trường hợp này, bạn sẽ phải phát hiện ra rằng máy khách đang yêu cầu phản hồi JSONP (thường bằng cách phát hiện tham số yêu cầu URL được gọi callback) và thay đổi cấu trúc dữ liệu một chút:

(NHẬN / bài viết / 123? Gọi lại = 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!"
            ]
        }
    }
});

Sau đó, trình xử lý phản hồi trên máy khách (trong trình duyệt web) phải có hàm JavaScript toàn cầu được gọi là displayBlogPostchấp nhận một đối số duy nhất. Hàm này sẽ phải xác định xem phản hồi có thành công hay không:

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

Vì vậy, chúng tôi đã chăm sóc khách hàng. Bây giờ, hãy chăm sóc máy chủ.

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

Và để sử dụng điều này trong trường hợp lỗi máy chủ:

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

Hoặc khi xác thực đầu vào của người dùng:

// 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;

Sau đó, bạn chỉ cần một cái gì đó lấy đối tượng phản hồi được trả về và chuyển đổi nó thành JSON và gửi phản hồi theo cách vui vẻ của nó.


Cảm ơn bạn đã trả lời! Tôi đã thực hiện giải pháp tương tự. Sự khác biệt duy nhất mà tôi không tự mình chuyển bất kỳ tin nhắn nào, chúng đã được đặt (xem câu hỏi cập nhật của tôi).
Grokking

-2

Tôi đã phải đối mặt với một cái gì đó tương tự, tôi đã làm 3 điều,

  1. Tạo một ExceptionHandler cho chính tôi được gọi là ABCException.

Vì tôi đang sử dụng Java & Spring

Tôi định nghĩa nó là

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

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

        }
    }

Sau đó gọi nó bất cứ nơi nào cần thiết, như thế này,

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

Và vâng, bạn cần tạo ExceptionHandler trong bộ điều khiển của mình nếu bạn đang sử dụng dịch vụ web dựa trên REST.

Chú thích với @ExceptionHandlernếu sử dụng Spring


Lập trình viên là về câu hỏi khái niệm và câu trả lời dự kiến ​​sẽ giải thích mọi thứ . Ném các đoạn mã thay vì giải thích giống như sao chép mã từ IDE sang bảng trắng: nó có thể trông quen thuộc và thậm chí đôi khi có thể hiểu được, nhưng nó cảm thấy kỳ lạ ... chỉ là lạ. Bảng trắng không có trình biên dịch
gnat
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.