In questa situazione, penso sempre prima all'interfaccia, quindi scrivo il codice PHP per supportarlo.
- È un'API REST, quindi sono indispensabili codici di stato HTTP significativi.
- Desideri che strutture di dati coerenti e flessibili vengano inviate da e verso il client.
Pensiamo a tutte le cose che potrebbero andare storte e ai loro codici di stato HTTP:
- Il server genera un errore (500)
- Errore di autenticazione (401)
- La risorsa richiesta non è stata trovata (404)
- I dati che stai modificando sono stati modificati da quando li hai caricati (409)
- Errori di convalida durante il salvataggio dei dati (422)
- Il cliente ha superato il tasso di richiesta (429)
- Tipo di file non supportato (415)
Nota, ce ne sono altri che puoi cercare in seguito.
Per la maggior parte delle condizioni di errore, è necessario restituire un solo messaggio di errore. Il422 Unprocessable Entity
risposta, che ho usato per "errori di convalida", potrebbe restituire più di un errore --- Uno o più errori per campo modulo.
Abbiamo bisogno di una struttura dati flessibile per le risposte agli errori.
Prendiamo ad esempio il 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!"
]
}
}
Contrastalo con semplici errori di convalida quando provi a POST qualcosa sul server:
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"
]
}
}
La chiave qui è il tipo di contenuto text/json
. Questo dice alle applicazioni client che possono decodificare il corpo della risposta con un decoder JSON. Se, ad esempio, non viene rilevato un errore interno del server e viene invece consegnata la pagina Web generica "Qualcosa è andato storto", il tipo di contenuto dovrebbe esseretext/html; charset=utf-8
tale che le applicazioni client non tentino di decodificare il corpo della risposta come JSON.
Questo sembra tutto trovare e dandy, fino a quando non è necessario supportare le risposte JSONP . È necessario restituire una 200 OK
risposta, anche per errori. In questo caso dovrai rilevare che il client richiede una risposta JSONP (in genere rilevando un parametro di richiesta URL chiamatocallback
) e modificare un po 'la struttura dei dati:
(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!"
]
}
}
});
Quindi il gestore risposte sul client (in un browser Web) dovrebbe avere una funzione JavaScript globale chiamata displayBlogPost
che accetta un singolo argomento. Questa funzione dovrebbe determinare se la risposta ha avuto esito positivo:
function displayBlogPost(response) {
if (response.status == 500) {
alert(response.data.errors.general[0]);
}
}
Quindi ci siamo presi cura del cliente. Ora prendiamoci cura del server.
<?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;
}
}
E per usarlo in caso di un errore del server:
try {
// some code that throws an exception
}
catch (Exception $ex) {
return new ResponseError(ResponseError::STATUS_INTERNAL_SERVER_ERROR, $ex->message);
}
O durante la convalida dell'input dell'utente:
// 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;
Successivamente, hai solo bisogno di qualcosa che prenda l'oggetto di risposta restituito e lo converta in JSON e invia la risposta nel modo giusto.