Mon implémentation REST renverra des erreurs dans JSON avec la structure suivante:
{
"http_response":400,
"dev_message":"There is a problem",
"message_for_user":"Bad request",
"some_internal_error_code":12345
}
Je suggère de créer un modèle de réponse spécial, où je peux transmettre les valeurs nécessaires pour les propriétés (dev_message, message_for_user, some_internal_error_code), et les renvoyer. Dans le code, cela ressemblerait à ceci:
$responseModel = new MyResponseModel(400,"Something is bad", etc...);
À quoi devrait ressembler ce modèle? Dois-je mettre en œuvre des méthodes, par exemple successResponse () où je ne transmettrai que des informations textuelles, et le code sera par défaut 200 là-bas? Je suis coincé avec ça. Et ceci est la première partie de ma question: dois-je mettre en œuvre ce modèle, est-ce une bonne pratique? Parce que pour l'instant, je retourne juste des tableaux directement à partir du code.
La deuxième partie concerne le système de code d'erreur. Les codes d'erreur seront décrits dans la documentation. Mais le problème que je rencontre est dans le code. Quelle est la meilleure façon de gérer les codes d'erreur? Dois-je les écrire à l'intérieur du modèle? Ou serait-il préférable de créer un service distinct pour gérer cela?
MISE À JOUR 1
J'ai implémenté une classe de modèle pour la réponse. C'est la réponse de Greg similaire, la même logique, mais en plus j'ai codé en dur erreurs écrites dans le modèle et voici à quoi cela ressemble:
class ErrorResponse
{
const SOME_ENTITY_NOT_FOUND = 100;
protected $errorMessages = [100 => ["error_message" => "That entity doesn't exist!"]];
...some code...
}
Pourquoi j'ai fait ça? Et pour quoi faire?
return new ErrorResponse(ErrorResponse::SOME_ENTITY_NOT_FOUND );
Si vous avez des suggestions pour améliorer cela, veuillez commenter.
Dans cette situation, je pense toujours à l'interface d'abord, puis j'écris PHP code pour la supporter).
Pensons à toutes les choses qui pourraient mal tourner et à leurs codes d'état HTTP:
Notez qu'il y en a d'autres que vous pouvez rechercher plus tard.
Pour la plupart des conditions d'échec, un seul message d'erreur doit être renvoyé. Le 422 Unprocessable Entity
la réponse, que j'ai utilisée pour les "erreurs de validation" pourrait renvoyer plusieurs erreurs --- Une ou plusieurs erreurs par champ de formulaire.
Nous avons besoin d'une structure de données flexible pour les réponses aux erreurs.
Prenons comme exemple, le 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!"
]
}
}
Comparez cela avec de simples erreurs de validation lorsque vous essayez de POST quelque chose au serveur:
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 clé ici est le type de contenu étant text/json
. Cela indique aux applications clientes qu'elles peuvent décoder le corps de réponse avec un décodeur JSON. Si, par exemple, une erreur de serveur interne n'est pas détectée et que votre page Web générique "Quelque chose s'est mal passé" est livrée à la place, le type de contenu doit être text/html; charset=utf-8
pour que les applications clientes n'essaient pas de décoder le corps de la réponse en JSON.
Cela ressemble à tout trouver et dandy, jusqu'à ce que vous ayez besoin de prendre en charge les réponses JSONP . Vous devez renvoyer un 200 OK
réponse, même en cas d'échecs. Dans ce cas, vous devrez détecter que le client demande une réponse JSONP (généralement en détectant un paramètre de demande d'URL appelé callback
) et modifier un peu la structure des données:
(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!"
]
}
}
});
Ensuite, le gestionnaire de réponse sur le client (dans un navigateur Web) doit avoir une fonction JavaScript globale appelée displayBlogPost
qui accepte un seul argument. Cette fonction devrait déterminer si la réponse a réussi:
function displayBlogPost(response) {
if (response.status == 500) {
alert(response.data.errors.general[0]);
}
}
Nous avons donc pris soin du client. Maintenant, prenons soin du serveur.
<?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;
}
}
Et pour l'utiliser en cas d'erreur de serveur:
try {
// some code that throws an exception
}
catch (Exception $ex) {
return new ResponseError(ResponseError::STATUS_INTERNAL_SERVER_ERROR, $ex->message);
}
Ou lors de la validation de la saisie utilisateur:
// 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;
Après cela, vous avez juste besoin de quelque chose qui prend l'objet de réponse retourné et le convertit en JSON et envoie la réponse sur son chemin joyeux.