この状況では、私は常に最初にインターフェイスを考え、次にそれをサポートするPHPコードを記述します。
- これはREST APIなので、意味のあるHTTPステータスコードは必須です。
- クライアントとの間で送信される一貫した柔軟なデータ構造が必要です。
失敗する可能性のあるすべてのことと、それらのHTTPステータスコードを考えてみましょう。
- サーバーはエラーをスローします(500)
- 認証失敗(401)
- 要求されたリソースが見つかりませんでした(404)
- 変更中のデータは、ロード後に変更されました(409)
- データの保存時の検証エラー(422)
- クライアントが要求率を超えました(429)
- サポートされていないファイルタイプ(415)
後で調査できる他のものがあることに注意してください。
ほとんどの障害状態では、返されるエラーメッセージは1つだけです。の422 Unprocessable Entity
私は「検証エラー」のために使用してきた応答は、複数のエラー---フォームフィールドごとに1つの以上のエラーを返すことができます。
エラー応答には柔軟なデータ構造が必要です。
、例として取ります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デコーダーで応答本文をデコードできることを伝えます。たとえば、内部サーバーエラーがキャッチされず、代わりに一般的な「何かが間違っている」Webページが配信される場合text/html; charset=utf-8
、クライアントアプリケーションが応答本文をJSONとしてデコードしないようにコンテンツタイプを設定する必要があります。
JSONP応答をサポートする必要があるまで、これはすべての発見とダンディに見えます。200 OK
失敗した場合でも、応答を返す必要があります。この場合、クライアントがJSONP応答を要求していることを検出する必要があります(通常は、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!"
]
}
}
});
次に、クライアント(Webブラウザー内)の応答ハンドラーにdisplayBlogPost
は、単一の引数を受け入れるグローバルJavaScript関数が必要です。この関数は、応答が成功したかどうかを判断する必要があります。
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に変換し、その応答を陽気な方法で送信するものが必要です。