In questa situazione, penso sempre all'interfaccia, quindi scrivo codice PHP per supportarla.
- È un'API REST, quindi i codici di stato HTTP significativi sono indispensabili.
- Desideri che strutture di dati coerenti e flessibili vengano inviate al e dal 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 lo hai caricato (409)
- Errori di convalida durante il salvataggio dei dati (422)
- Il client ha superato il tasso di richiesta (429)
- Tipo di file non supportato (415)
Nota, ce ne sono altri che puoi ricercare in seguito.
Per la maggior parte delle condizioni di errore, è necessario restituire un solo messaggio di errore. La risposta 422 Unprocessable Entity
, che ho utilizzato 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 di errore.
Prendi come esempio, 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!"
]
}
}
Confrontalo con semplici errori di convalida quando provi a pubblicare 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 che è text/json
. Questo dice alle applicazioni client che possono decodificare il corpo della risposta con un decodificatore JSON. Se, ad esempio, non viene rilevato un errore interno del server e la tua pagina Web generica "Qualcosa è andato storto" viene consegnata, il tipo di contenuto dovrebbe essere text/html; charset=utf-8
in modo che le applicazioni client non tenteranno di decodificare il corpo della risposta come JSON.
Questo sembra tutto trovare e dandy, finché non è necessario supportare le JSONP risposte. È necessario restituire una risposta 200 OK
, anche per gli errori. In questo caso dovrai rilevare che il client richiede una risposta JSONP (in genere rilevando un parametro di richiesta URL chiamato callback
) e modifica un po 'la struttura 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 di risposta 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 successo:
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 usare questo nel 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);
}
Oppure 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;
Dopodiché, hai solo bisogno di qualcosa che prenda l'oggetto risposta restituito e lo converta in JSON e manda la risposta a modo suo.