วิธีที่ดีที่สุดในการสร้างรูปแบบการตอบสนองข้อผิดพลาด REST API และระบบรหัสข้อผิดพลาดคืออะไร?


15

การใช้งาน REST ของฉันจะส่งคืนข้อผิดพลาดใน JSON ด้วยโครงสร้างถัดไป:

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

ฉันแนะนำให้สร้างโมเดลการตอบกลับพิเศษซึ่งฉันสามารถส่งผ่านค่าที่ต้องการสำหรับคุณสมบัติ (dev_message, message_for_user, some_internal_error_code) และส่งคืนได้ ในรหัสมันจะคล้ายกับสิ่งนี้:

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

รุ่นนี้มีหน้าตาเป็นอย่างไร ฉันควรใช้วิธีการอย่างเช่น successResponse () โดยที่ฉันจะส่งผ่านเฉพาะข้อมูลตัวอักษรและรหัสจะเป็นค่าเริ่มต้น 200 รายการ ฉันติดอยู่กับเรื่องนี้ และนี่เป็นส่วนแรกของคำถามของฉัน: ฉันจำเป็นต้องใช้โมเดลนี้หรือไม่ เพราะตอนนี้ฉันเพิ่งกลับอาร์เรย์โดยตรงจากรหัส

ส่วนที่สองเป็นเรื่องเกี่ยวกับระบบรหัสข้อผิดพลาด รหัสข้อผิดพลาดจะอธิบายไว้ในเอกสาร แต่ปัญหาที่ฉันพบอยู่ในรหัส วิธีที่ดีที่สุดในการจัดการรหัสข้อผิดพลาดคืออะไร? ฉันควรเขียนมันไว้ในโมเดลหรือไม่? หรือมันจะเป็นการดีกว่าถ้าจะสร้างบริการแยกต่างหากสำหรับจัดการสิ่งนี้

อัพเดท 1

ฉันใช้คลาสจำลองเพื่อการตอบสนอง มันเป็นคำตอบที่คล้ายกันของ Greg ตรรกะเดียวกัน แต่นอกจากนี้ฉันมีข้อผิดพลาดในการเขียนhardcodedในรูปแบบและนี่เป็นลักษณะ:

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

     ...some code...
    }

ทำไมฉันถึงทำอย่างนี้? และเพื่ออะไร

  1. มันดูเท่ในรหัส: return new ErrorResponse(ErrorResponse::SOME_ENTITY_NOT_FOUND );
  2. ง่ายต่อการเปลี่ยนข้อความผิดพลาด ข้อความทั้งหมดอยู่ในที่เดียวแทนที่จะเป็นคอนโทรลเลอร์ / บริการ / ฯลฯ หรืออะไรก็ตามที่คุณจะวางไว้

หากคุณมีข้อเสนอแนะในการปรับปรุงโปรดแสดงความคิดเห็น

คำตอบ:


13

ในสถานการณ์นี้ฉันมักจะนึกถึงอินเทอร์เฟซก่อนแล้วจึงเขียนโค้ด PHP เพื่อรองรับ

  1. เป็น REST API ดังนั้นจึงต้องมีรหัสสถานะ HTTP ที่มีความหมาย
  2. คุณต้องการให้โครงสร้างข้อมูลที่สอดคล้องและยืดหยุ่นถูกส่งไปและกลับจากไคลเอนต์

ลองนึกถึงทุกสิ่งที่อาจผิดและรหัสสถานะ HTTP:

  • เซิร์ฟเวอร์ส่งข้อผิดพลาด (500)
  • การตรวจสอบล้มเหลว (401)
  • ไม่พบทรัพยากรที่ร้องขอ (404)
  • ข้อมูลที่คุณกำลังแก้ไขมีการเปลี่ยนแปลงนับตั้งแต่คุณโหลด (409)
  • ข้อผิดพลาดในการตรวจสอบความถูกต้องเมื่อบันทึกข้อมูล (422)
  • ลูกค้าได้เกินอัตราการร้องขอของพวกเขา (429)
  • ประเภทไฟล์ที่ไม่รองรับ (415)

หมายเหตุมีคนอื่นที่คุณสามารถค้นคว้าได้ในภายหลัง

สำหรับเงื่อนไขความล้มเหลวส่วนใหญ่จะมีข้อความข้อผิดพลาดเดียวที่จะส่งคืน การ422 Unprocessable Entityตอบสนองซึ่งฉันใช้สำหรับ "ข้อผิดพลาดในการตรวจสอบความถูกต้อง" อาจส่งคืนข้อผิดพลาดมากกว่าหนึ่งข้อ --- ข้อผิดพลาดอย่างน้อยหนึ่งข้อต่อแบบฟอร์มฟิลด์

เราต้องการโครงสร้างข้อมูลที่ยืดหยุ่นสำหรับการตอบสนองข้อผิดพลาด

ยกตัวอย่างเช่น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!"
        ]
    }
}

ตรงกันข้ามที่มีข้อผิดพลาดการตรวจสอบง่ายเมื่อพยายาม POST บางสิ่งไปยังเซิร์ฟเวอร์:

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

text/jsonที่สำคัญที่นี่พวกเขาเป็นชนิดที่เป็นเนื้อหา สิ่งนี้บอกแอปพลิเคชันไคลเอนต์ว่าสามารถถอดรหัสเนื้อความการตอบสนองด้วยตัวถอดรหัส JSON หากกล่าวว่าข้อผิดพลาดเซิร์ฟเวอร์ภายในไม่ถูกตรวจจับและมีการส่งมอบหน้าเว็บ "บางอย่างผิดปกติ" ของคุณแทนประเภทเนื้อหาควรเป็นtext/html; charset=utf-8เช่นนั้นแอปพลิเคชันไคลเอนต์จะไม่พยายามถอดรหัสเนื้อหาการตอบสนองเป็น JSON

สิ่งนี้จะค้นหาและน่าสนใจทั้งหมดจนกว่าคุณจะต้องการสนับสนุนการตอบกลับJSONP คุณต้องส่งคืนการ200 OKตอบกลับแม้จะล้มเหลว ในกรณีนี้คุณจะต้องตรวจสอบว่าลูกค้าร้องขอการตอบสนอง JSONP (โดยปกติจะตรวจพบพารามิเตอร์คำขอ URL ที่เรียกว่าcallback) และเปลี่ยนโครงสร้างข้อมูลเล็กน้อย:

(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!"
            ]
        }
    }
});

จากนั้นตัวจัดการการตอบสนองบนไคลเอนต์ (ในเว็บเบราว์เซอร์) ควรมีฟังก์ชั่น JavaScript ทั่วโลกที่เรียกว่าdisplayBlogPostซึ่งยอมรับอาร์กิวเมนต์เดียว ฟังก์ชั่นนี้จะต้องพิจารณาว่าการตอบสนองนั้นประสบความสำเร็จหรือไม่:

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

ดังนั้นเราจึงดูแลลูกค้า ทีนี้มาดูแลเซิร์ฟเวอร์กันดีกว่า

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

และเพื่อใช้สิ่งนี้ในกรณีที่เซิร์ฟเวอร์เกิดข้อผิดพลาด:

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

หรือเมื่อตรวจสอบการป้อนข้อมูลของผู้ใช้:

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

หลังจากนั้นคุณเพียงต้องการบางสิ่งที่ใช้วัตถุตอบกลับที่ส่งคืนและแปลงเป็น JSON และส่งการตอบสนองด้วยวิธีที่สนุกสนาน


ขอบคุณสำหรับคำตอบ! ฉันใช้โซลูชันที่คล้ายกัน ความแตกต่างเพียงอย่างเดียวที่ฉันไม่ได้ส่งต่อข้อความใด ๆ ด้วยตัวเองมีการตั้งค่าไว้แล้ว (ดูคำถามที่อัปเดตของฉัน)
Grokking

-2

ฉันกำลังเผชิญสิ่งที่คล้ายกันฉันทำ 3 สิ่ง

  1. สร้าง ExceptionHandler สำหรับตัวฉันเองที่เรียกว่า ABCException

ตั้งแต่ฉันใช้ Java & Spring

ฉันกำหนดไว้ว่า

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

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

        }
    }

จากนั้นเรียกมันว่าทุกที่ที่ต้องการเช่นนี้

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

และใช่คุณต้องทำการ ExceptionHandler ในคอนโทรลเลอร์ของคุณหากคุณใช้เว็บเซอร์แบบ REST

อธิบายด้วย@ExceptionHandlerถ้าใช้ Spring


โปรแกรมเมอร์เป็นคำถามเกี่ยวกับแนวคิดและคำตอบที่คาดว่าจะอธิบายสิ่งต่างๆ การทิ้งรหัสทิ้งแทนที่จะอธิบายเป็นเหมือนการคัดลอกรหัสจาก IDE ไปยังไวท์บอร์ด: มันอาจดูคุ้นหูและบางครั้งก็เข้าใจได้ แต่มันให้ความรู้สึกแปลก ๆ ... มันแปลก ๆ ไวท์บอร์ดไม่มีคอมไพเลอร์
gnat
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.