2013-08-27 173 views
24

我正在編寫一個REST API,並且我偶然發現了一個問題。什麼是返回驗證錯誤的最佳方式。REST API錯誤代碼返回結構

到現在爲止我已經回到傾倒入一個常規錯誤代碼的錯誤信息(比方說,例如錯誤的請求)

{ 
    "status": 400, 
    "error": { 
     "code": 1, // General bad request code 
     "message": [ 
       "The Key \"a\" is missing", 
       "The Key \"b\" is missing", 
       "The Key \"c\" is missing", 
       "Incorrect Format for field \"y\"" 
     ] 
    } 

) 

我研究多一點關於應該如何良好的API響應應該像我以爲以下選項:

  1. 停在第一個遇到的錯誤並返回與特定錯誤代碼

    響應
  2. 解析所有請求數據並返回多個字段驗證錯誤。

    { 
        "status": 400, 
        "error": { 
        "code": 1 //General bad Request code 
        "message": "Bad Request", 
        "developer_message": "Field validation errors." 
        "more_info": "www.api.com/help/errors/1", 
        "error_details": { 
          0: { 
            "code": 2 // Specific field validation error code 
            "message": "Field \"x\" is missing from the array structure", 
            "developer_message": "The request structure must contain the following fields {a,b,c{x,y,z}}", 
            "more_info": "www.api.com/help/errors/2" 
           }, 
    
          1: { 
            "code": 3 // Specific field validation error code 
            "message": "Incorrect Format for field \"y\"", 
            "developer_message": "The field \"y\" must be in the form of \"Y-m-d\"", 
            "more_info": "www.api.com/help/errors/3" 
           } 
            } 
         } 
        } 
    

在我看來選項2將是正確的方式(它提供了更多有用的信息給開發者/最終用戶和服務器的負載可能較低(更低請求/無需重新驗證有效的數據/不需要計算簽名和驗證用戶)),但是我正在徘徊什麼是最佳實踐,以及是否有另一種方式來處理這類問題。

此外,我認爲選擇1仍然是有效的,如果我在腳本的流程得到一個致命的錯誤。(未驗證錯誤)

請注意,代碼只是一個簡單的數組只是這樣更容易跟隨。響應格式將是JSON或XML。

+0

我想知道是否有人去#2,也許有任何改進,所以我打開了賞金。 – Ski

+0

此API用於什麼以及錯誤消息的目的是什麼?這些消息是否會顯示給最終用戶?每秒/分鐘/每天預計有多少個請求?沒有這些信息,你的問題的答案就不可能是準確的。你沒有答案,因爲這個問題太廣泛了,這取決於API的使用。 – skobaljic

回答

0

就我個人而言,我會給用戶更少的細節,並將開發人員需要的錯誤轉儲到數據庫日誌表或系統日誌中。由於您使用的是JSON,而這在Apache服務器上最爲常見,您的代碼看起來很可能是PHP(但您的帶花括號的代碼示例可能是許多源自PASCAL的語言,例如C,C#PERL,PHP, CSHARP)。如果您還不知道如何在php http://php.net/manual/en/function.syslog.php中,那麼如何將輸出自定義錯誤添加到系統日誌中。如果你正在使用JSON和CSharp的稀有配置IIS,.NET庫也可以做類似的工作。如果您在發生錯誤時向用戶提供了太多信息,那麼您將來也會給黑客一種探測您的網站的方式。

+0

我假設在這種情況下,數據從輸入表單傳遞的情況下,驗證必須完全在前端完成,所以如果無效值傳遞給後端,假設前端代碼中出現錯誤? – Ski

+0

如果前端錯誤,我討厭最多的是因爲它斷開連接,所以我在考慮一個異步的Ajax post到服務器端的php腳本是否值得此刻,這取決於錯誤的嚴重程度。如果它確實可以將其顯示給用戶,那麼它很瑣碎。如果客戶端出現錯誤,那麼JSON甚至可能不在公式中。你現在正在談論純粹的JQUERY或Javascript錯誤?無效的表單輸入通常只是輸入框以紅色點亮並帶有一般信息。 – 2015-04-30 17:49:48

+0

簡而言之,發生在客戶端的任何事情都可以通過AJAX發送給服務器端,訪問Facebook並使用一個名爲firebug的工具並選擇服務器活動帖子,並且您可能會驚訝發送回服務器的帖子數量。我正在使用這個例子,因爲我仍然試圖找出如何重新打開一個組。這是一個漫長的故事,我不能說太多。 – 2015-04-30 18:05:36

3

我已經使用了#2自己幾次。比#1好嗎?我認爲這取決於你的API被用於什麼。

我喜歡#2,因爲它給正在測試API的開發人員提供一些測試請求,快速瞭解他在請求中所做的所有錯誤/錯誤,因此他立即知道他必須修復哪些錯誤/錯誤使該請求有效。如果你逐一返回錯誤(如#1),你必須不斷重試請求,並且交叉手指希望這次有效。

但正如我所說#2對開發人員非常有用,但其原因並不適用於最終用戶。最終用戶通常不關心它是如何實施的。軟件是否正在執行返回5個錯誤的1個請求或每個返回1個錯誤的5個後續請求。
只要在客戶端處理得當,最終用戶不應該注意到其中的差異。當然如何處理,當然很取決於客戶端

除了加速開發之外,#2(在生產中)的另一個好處是它只需要較少的請求,這當然會降低服務器負載。


I would like to know if anyone went #2 and maybe have any improvements on it so I opened a bounty.

肯定有被做了改進。實際上,可以省略身體中的一些數據。

{ 
    "status": 400, 
    "error": { 
    "code": 1 //General bad Request code 
    "message": "Bad Request", 
    "developer_message": "Field validation errors." 
    "more_info": "www.api.com/help/errors/1", 
    "error_details": { 
      0: { 
        "code": 2 // Specific field validation error code 
        "message": "Field \"x\" is missing from the array structure", 
        "developer_message": "The request structure must contain the following fields {a,b,c{x,y,z}}", 
        "more_info": "www.api.com/help/errors/2" 
       }, 

      1: { 
       (
        "code": 3 // Specific field validation error code 
        "message": "Incorrect Format for field \"y\"", 
        "developer_message": "The field \"y\" must be in the form of \"Y-m-d\"", 
        "more_info": "www.api.com/help/errors/3" 
       ) 
      } 
) 

對於HTTP響應,狀態碼不應放在主體中,而應放在標題中。這意味着這裏可以省略"status": 400"message": "Bad Request"。 400應該是響應的狀態碼,400意味着錯誤請求。這是一個HTTP標準,不必在響應中解釋。此外,"developer_message": "Field validation errors."也是重複的,因爲具體的錯誤已經包含在每個單獨的錯誤中,所以我們可以將其忽略。

這使得

{ 
    "error": { 
    "code": 1 //General bad Request code 
    "more_info": "www.api.com/help/errors/1", 
    "error_details": { 
      0: { 
        "code": 2 // Specific field validation error code 
        "message": "Field \"x\" is missing from the array structure", 
        "developer_message": "The request structure must contain the following fields {a,b,c{x,y,z}}", 
        "more_info": "www.api.com/help/errors/2" 
       }, 

      1: { 
       (
        "code": 3 // Specific field validation error code 
        "message": "Incorrect Format for field \"y\"", 
        "developer_message": "The field \"y\" must be in the form of \"Y-m-d\"", 
        "more_info": "www.api.com/help/errors/3" 
       ) 
      } 
) 

"code": 1 //General bad Request code 
"more_info": "www.api.com/help/errors/1", 

這兩條線沒有真正意義了現在。他們也沒有要求,因爲每個錯誤都有它自己的代碼和信息鏈接,所以我們可能會剝離這些線路爲好,離開這個

{ 
    "error": { 
    "error_details": { 
      0: { 
        "code": 2 // Specific field validation error code 
        "message": "Field \"x\" is missing from the array structure", 
        "developer_message": "The request structure must contain the following fields {a,b,c{x,y,z}}", 
        "more_info": "www.api.com/help/errors/2" 
       }, 

      1: { 
       (
        "code": 3 // Specific field validation error code 
        "message": "Incorrect Format for field \"y\"", 
        "developer_message": "The field \"y\" must be in the form of \"Y-m-d\"", 
        "more_info": "www.api.com/help/errors/3" 
       ) 
      } 
) 

的400個狀態碼已經表示出現了錯誤,所以你不」因爲我們已經知道有錯誤,所以不必再指出"error": {error details}。錯誤列表可以簡單地成爲根對象:

[ 
    { 
     "code": 2//Specificfieldvalidationerrorcode 
     "message": "Field \"x\" is missing from the array structure", 
     "developer_message": "The request structure must contain the following fields {a,b,c{x,y,z}}", 
     "more_info": "www.api.com/help/errors/2" 
    }, 
    { 
     "code": 3//Specificfieldvalidationerrorcode 
     "message": "Incorrect Format for field \"y\"", 
     "developer_message": "The field \"y\" must be in the form of \"Y-m-d\"", 
     "more_info": "www.api.com/help/errors/3" 
    } 
] 

因此,所有現在遺留在身體中的僅僅是一個錯誤列表。

狀態碼在響應標題中指定。
詳細信息在響應主體中指定。

+1

同意所描述的方法:應該改進#2以避免[數據重複](http://en.wikipedia.org/wiki/Data_redundancy),因此如果出現兩次,它也可能是狀態不一致。這是許多異常處理系統通常採用的,例如:http://www.asp.net/web-api/overview/error-handling/exception-handling –

0

首先,您會爲客戶提供Rest API方法的文檔。因此,客戶/開發人員希望爲參數提供有效的數據。

現在說#1是執行Rest API的最佳方法。開發者的責任是儘可能減少服務器的使用。因此,如果您遇到任何致命錯誤,請使用相應的錯誤代碼和錯誤消息構建響應並將其返回。

此外,我們不能確定在我們遇到的錯誤之後還有更多錯誤。因此,解析其餘數據是毫無意義的。考慮到最糟糕的情況,它不會奏效。

+0

*開發人員的責任是將服務器使用率降至最大可能的程度*但是,如果你逐個返回錯誤(需要後續調用),那麼情況並非如此 –

16

讓我們來看看Facebook's Graph API。這很困難,而且很可能會產生很多錯誤。以下是Facebook的上的API返回錯誤:

{ 
    "error": { 
    "message": "Message describing the error", 
    "type": "OAuthException", 
    "code": 190, 
    "error_subcode": 460, 
    "error_user_title": "A title", 
    "error_user_msg": "A message" 
    } 
} 

他們試圖使圖形API儘可能有用,但他們似乎有一個代碼和子碼(Ref)返回一個特定的錯誤。每個錯誤都有自己的代碼的事實意味着搜索所述代碼或消息作爲調試的起點更容易。這可能就是他們爲什麼不在他們的官方錯誤響應中積累錯誤信息的原因。如果Facebook足夠好並且方便,那對我們來說可能已經足夠了。

樣的錯誤響應:

{ 
    "error": { 
    "message": "(#200) Must have a valid access_token to access this endpoint", 
    "type": "OAuthException", 
    "code": 200 
    } 
} 

"error": { 
    "message": "(#604) Your statement is not indexable. The WHERE clause must contain 
    an indexable column. Such columns are marked with * in the tables linked from 
    http://developers.facebook.com/docs/reference/fql ", 
    "type": "OAuthException", 
    "code": 604 
} 

再有就是JSend其中「是規定了從Web服務器如何JSON響應一些規則規範應被格式化「。他們的目標是:

There are lots of web services out there providing JSON data, and each has its own way of formatting responses. Also, developers writing for JavaScript front-ends continually re-invent the wheel on communicating data from their servers. While there are many common patterns for structuring this data, there is no consistency in things like naming or types of responses. Also, this helps promote happiness and unity between backend developers and frontend designers, as everyone can come to expect a common approach to interacting with one another.

下面是一個簡單的錯誤消息:

{ 
    "status" : "fail", 
    "data" : { "title" : "A title is required" } 
} 

它看起來像Facebook和這組試圖建立類似的行業標準都選擇供你選擇1#。


賞金問題

針對的賞金要求「如果有人去#2,也許上有任何改進?」,有來自Pragmatic RESTful API,指出設計模式:

Validation errors will need a field breakdown. This is best modeled by using a fixed top-level error code for validation failures and providing the detailed errors in an additional errors field, like so:

{ 
    "code" : 1024, 
    "message" : "Validation Failed", 
    "errors" : [ 
    { 
     "code" : 5432, 
     "field" : "first_name", 
     "message" : "First name cannot have fancy characters" 
    }, 
    { 
     "code" : 5622, 
     "field" : "password", 
     "message" : "Password cannot be blank" 
    } 
    ] 
} 
1

我最近使用了Rest API,它會在結果中返回多個警告或錯誤。從您的樣品#2開始,如下我將修改它:

{ 
    "status": 400, 
    "results" : null, 
    "warnings": { 
     0: { 
       // Build a warning message here, sample text to show concept 
       "code": 1 // Specific field validation error code 
       "message": "It is no longer neccessary to put .js on the URL" 
      } 
    } 
    "errors": { 
     0: { 
       "code": 2 // Specific field validation error code 
       "message": "Field \"x\" is missing from the array structure" 
       "developer_message": "The request structure must contain the following fields {a,b,c{x,y,z}}", 
      }, 
     1: { 
       "code": 3 // Specific field validation error code 
       "message": "Incorrect Format for field \"y\"", 
       "developer_message": "The field \"y\" must be in the form of \"Y-m-d\"" 
      } 
     } 
    } 

這將爲您提供結果,與多個警告,或根據需要在您的響應錯誤的能力。

是的,這確實在結構中有一些膨脹,但它也爲開發人員提供了一個簡單的接口,以便始終將其數據恢復到同一結構中。

我還要刪除下列項目恕我直言,他們應該在API文檔(如何使用錯誤代碼尋求幫助),而不是在每一個錯誤:

"more_info": "www.api.com/help/errors/2" 
"more_info": "www.api.com/help/errors/3" 

本着同樣的精神,我m不知道你是否需要消息和developer_message。它們看起來是多餘的,並且當調用者未能正確提供數據時,您試圖從API提供用戶錯誤消息。

1

API不適用於人類。因此您不需要返回詳細的錯誤文本。你甚至可以返回一個錯誤代碼,這意味着「缺少參數」。只是不要忘了記錄它。

+0

API也適用於人類,開發人員使用API​​是開發人員。此外,也許錯誤消息必須直接傳遞給最終用戶。 –