REST codes D'erreur de L'API structure de retour

j'écris une API REST et je suis tombé sur un problème. Quelle est la meilleure façon de retourner les erreurs de validation.

Jusqu'à présent j'ai retourné les messages d'erreur déversés dans un code d'erreur général (disons une mauvaise requête par exemple)

{
    "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""
         ]
    }

)

j'ai fait un peu plus de recherches sur l'apparence d'une bonne réponse API et j'ai pensé aux options suivantes:

  1. Arrêter à la première erreur rencontrée et un retour réponse avec le code d'erreur spécifique

    {
       "status": 400, //Same as the HTTP header returned
       "error" {
            "code": 1, // 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/1"
        }
    )
    
  2. analyser toutes les données de la demande et retourner plusieurs erreurs de validation de champ.

    {
      "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"
                   }
                       }
          }
      }
    

à mon avis, l'option 2 serait la bonne (elle donne des informations plus utiles aux développeurs/utilisateurs finaux et la charge du serveur pourrait être plus faible(moins de requêtes/pas besoin de revalider des données valides/pas besoin de calculer la signature et d'authentifier l'utilisateur), mais je me demande quelles sont les meilleures pratiques, et si il y a une autre façon de traiter ce genre de problèmes.

je pense aussi que l'option 1 est toujours valide si j'obtiens une seule erreur fatale dans le flux du script.(pas d'erreurs de validation)

veuillez noter que le code n'est qu'un simple tableau pour qu'il soit plus facile à suivre. Le format de réponse sera JSON ou XML.

25
demandé sur Hackerman 2013-08-27 19:47:22

6 réponses

examinons API graphique de Facebook. Cela est durement frappé, et un grand nombre d'erreurs sont très probablement générés. Voici ce que Facebook retourne sur une erreur API:

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

ils essayent de rendre L'API Graph aussi utile que possible, mais ils semblent renvoyer une erreur spécifique avec un code et un sous-code ( Ref). Le fait que chaque erreur ait son propre code signifie qu'il est plus facile de rechercher ledit code ou message comme point de départ pour le débogage. C'est probablement pourquoi ils n'accumulent pas de messages d'erreur dans leur réponse officielle. Si c'est assez bon et pratique pour Facebook, il est probablement assez bon pour nous.

exemples de réponses d'erreur:

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

et

"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
}

Puis il y a JSend which " est une spécification qui fixe certaines règles pour le formatage des réponses JSON des serveurs web."Leur but est:

Il y a beaucoup de services web là-bas fournissant des données JSON, et chacun a sa propre façon de formater les réponses. En outre, les développeurs écrivant pour JavaScript front-ends continuellement réinventer la roue sur la communication des données à partir de leurs serveurs. Bien qu'il y ait de nombreux modèles communs pour structurer ces données, il n'y a pas d'uniformité dans des choses comme les noms ou les types de réponses. En outre, cela contribue à promouvoir le bonheur et l'unité entre les développeurs backend et les designers frontend, car tout le monde peut en venir à s'attendre à un approche en interaction les uns avec les autres.

Voici un exemple de message d'erreur:

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

il semble que Facebook et ce groupe qui essaie de se mettre à la norme de l'industrie optent pour votre choix #1.


Question De Prime

En réponse à la générosité demande de "si quelqu'un est allé #2 et a peut-être des améliorations sur elle?", il est un modèle de conception à partir de Pragmatic RESTful API que états:

les erreurs de Validation nécessiteront une ventilation des champs. La meilleure façon de le modéliser est d'utiliser un code d'erreur fixe de niveau supérieur pour les échecs de validation et de fournir les erreurs détaillées dans un champ d'erreurs supplémentaire, comme suit:

{
  "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"
    }
  ]
}
19
répondu Drakes 2015-05-07 09:19:14

j'ai utilisé #2 moi-même quelques fois. Est-il mieux que le #1? Je pense que cela dépend de l'utilité de votre API.

j'aime #2, car il donne un développeur qui est de tester l'API avec quelques appels de test un aperçu rapide de toutes les erreurs qu'il a fait en une demande, de sorte qu'il sait immédiatement les erreurs/erreurs qu'il a à résoudre à en faire la demande valide. Si vous retournez les erreurs une par une (comme dans #1) vous devez continuer à revenir sur la demande et croiser les doigts en espérant qu'il sera valide cette fois.

Mais comme je l'ai dit #2 est très utile pour les développeurs, mais les raisons ne s'applique pas aux utilisateurs finaux. Les utilisateurs finaux ne se soucient généralement pas comment il est mis en œuvre. Si le logiciel fait 1 requête qui renvoie 5 erreurs ou 5 requêtes suivantes qui renvoient 1 erreur chacune.

Tant que cela est bien géré dans le client, l'utilisateur final ne devrait pas remarquer la différence. Comment gérer cela bien sûr dépend beaucoup de ce que le client réellement .

en plus d'accélérer le développement, un autre avantage de #2 (en production) est qu'il nécessite moins de requêtes à faire, ce qui diminue bien sûr la charge du serveur.


je voudrais savoir si quelqu'un est allé #2 et peut-être avoir des améliorations sur elle alors j'ai ouvert un bounty.

bien sûr qu'il y a des améliorations à apporter. Comme il est, il ya certaines données dans le corps qui peuvent être omettre.

{
  "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"
                )
            }
)

avec les réponses HTTP, le code d'état ne doit pas aller dans le corps, mais dans l'en-tête. Cela signifie que "status": 400 et "message": "Bad Request" peut être omis ici. 400 devrait être le code d'état de la réponse, et 400 signifie Bad Request. Il s'agit D'un standard HTTP qui n'a pas à être expliqué dans la réponse. Aussi "developer_message": "Field validation errors." est une sorte de duplicata, puisque les erreurs spécifiques sont déjà incluses dans chaque erreur séparée, donc nous pourrions laisser cela de côté.

Que feuilles

{
  "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",

ces deux lignes n'ont plus vraiment de sens maintenant. Ils ne sont pas non plus nécessaires, puisque chaque erreur a son propre code et lien d'information, donc nous pourrions rayer ces lignes aussi bien, en laissant ceci

{
  "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"
                )
            }
)

le code de statut 400 indique déjà qu'il y a eu une erreur, donc vous n'avez pas à indiquer "error": {error details} plus maintenant, parce que nous savons déjà qu'il y avait une erreur. La liste des erreurs peut simplement devenir la racine objet:

[
    {
        "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"
    }
]

donc tout ce qui reste dans le corps maintenant est simplement une liste d'erreurs.

Le code d'état est spécifié dans l'en-tête de réponse.

Les détails sont spécifiés dans le corps de réponse.

3
répondu Tim Castelijns 2015-05-01 12:17:08

j'ai récemment travaillé contre une API Rest qui renverrait plusieurs avertissements ou erreurs dans les résultats. À partir de votre échantillon #2, je le modifierais comme suit:

{
  "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\""
           }
      }
  }

cela vous fournirait la capacité de fournir des résultats, avec de multiples avertissements ou erreurs si nécessaire dans votre réponse.

Et oui, ce ne sont quelques ballonnement dans la structure, mais il fournit également une interface facile pour un développeur de toujours récupérer leurs données dans le même structure.

je voudrais aussi supprimer les éléments suivants comme IMHO ils devraient être dans les docs API (comment trouver de l'aide en utilisant un code d'erreur) au lieu de sur chaque erreur:

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

dans le même ordre d'idées, Je ne suis pas sûr que vous ayez besoin à la fois du message et de developer_message. Ils semblent redondants et comme si vous essayiez de fournir des messages d'erreur utilisateur de l'API lorsque l'appelant n'a pas fourni les données correctement.

1
répondu Martin Noreke 2015-05-06 18:00:27

tout d'abord, vous auriez fourni de la documentation pour les méthodes de L'API Rest pour les clients. Donc, il est attendu du client/développeur de fournir des données valides pour les paramètres.

maintenant que j'ai dit que #1 est la meilleure façon de faire L'API Rest. La responsabilité d'un développeur est de réduire au maximum l'utilisation du serveur. Donc si vous rencontrez une erreur fatale, construisez une réponse avec le code d'erreur correspondant et le message d'erreur et retournez il.

de plus, nous ne pouvons pas être sûrs qu'il y ait plus d'erreurs après celle que nous avons rencontrée. Il est donc inutile d'analyser le reste des données. Il ne fonctionnera pas bien si l'on considère le pire des cas.

0
répondu Kamal Kannan 2015-05-06 09:37:14

les API ne sont pas pour les humains. Par conséquent, vous n'avez pas besoin de retourner les textes d'erreur détaillés. Vous pouvez même retourner un code d'erreur qui signifie "paramètre manquant". Il suffit de ne pas oublier de le documenter.

-1
répondu Mustafa Dokumacı 2015-05-07 11:55:14

personnellement, je donnerais aux utilisateurs moins de détails et supprimerais les erreurs nécessaires aux développeurs dans une table de journalisation de base de données ou des journaux système. En raison du fait que vous utilisez JSON et qui est le plus commun sur les serveurs Apache et votre code semble susceptible d'être php (mais votre exemple de code avec des accolades curly pourrait être un certain nombre de langues originaires de PASCAL eg. C, C#, PERL, PHP, C#). Voici comment mettre des erreurs de sortie personnalisées dans les journaux système Si vous ne savez pas déjà comment en php http://php.net/manual/en/function.syslog.php