Je suis nouveau dans REST et j'ai constaté que, dans certains services RESTful, ils utilisent un URI de ressource différent pour update/get/delete et Create. Tel que
Je suis un peu confus à propos de cette convention de nommage URI. Que devrions-nous utiliser pluriel ou singulier pour la création de ressources? Quels devraient être les critères en décidant cela?
Le principe d'utilisation de /resources
est qu'il représente "toutes" les ressources. Si vous faites un GET /resources
, vous retournerez probablement toute la collection. En postant à /resources
, vous ajoutez à la collection.
Cependant, les ressources individuelles sont disponibles sur/resource. Si vous faites un GET /resource
, vous aurez probablement une erreur, car cette requête n’a aucun sens, alors que /resource/123
a un sens parfait.
Utiliser /resource
au lieu de /resources
ressemble à ce que vous feriez si vous utilisiez, par exemple, un système de fichiers et une collection de fichiers et que /resource
est le "répertoire" avec le chaque fichier 123
, 456
.
Aucune des deux solutions n'est bonne ou mauvaise, allez avec ce que vous préférez.
Pour moi, il est préférable d'avoir un schéma que vous pouvez mapper directement au code (facile à automatiser), principalement parce que le code est ce qui va se passer des deux côtés.
GET /orders <---> orders
POST /orders <---> orders.Push(data)
GET /orders/1 <---> orders[1]
PUT /orders/1 <---> orders[1] = data
GET /orders/1/lines <---> orders[1].lines
POST /orders/1/lines <---> orders[1].lines.Push(data)
Je ne vois pas l'intérêt de le faire non plus et je pense que ce n'est pas la meilleure conception d'URI. En tant qu'utilisateur d'un service RESTful, je m'attendrais à ce que la ressource de liste porte le même nom, que j'accède à la liste ou à une ressource spécifique "dans" la liste. Vous devez utiliser les mêmes identificateurs, que vous souhaitiez utiliser la ressource de liste ou une ressource spécifique.
pluriel
orders/
obtient une liste d'index des commandes.Par exemple:
GET /resources
- renvoie une liste d'éléments de ressources
POST /resources
- crée un ou plusieurs éléments de ressource
PUT /resources
- met à jour un ou plusieurs éléments de ressource
PATCH /resources
- met à jour partiellement un ou plusieurs éléments de ressource
DELETE /resources
- supprime tous les éléments de ressource
Et pour les éléments de ressource uniques:
GET /resources/:id
- renvoie un élément de ressource spécifique basé sur le paramètre :id
POST /resources/:id
- crée un élément de ressource avec l'id spécifié (nécessite une validation)
PUT /resources/:id
- met à jour un élément de ressource spécifique
PATCH /resources/:id
- met à jour partiellement un élément de ressource spécifique
DELETE /resources/:id
- supprime un élément de ressource spécifique
Pour les défenseurs du singulier, réfléchissez de la façon suivante: demandez-vous une personne pour une order
et attendez-vous une chose ou une liste de choses? Alors, pourquoi vous attendriez-vous à ce qu'un service renvoie une liste d'éléments lorsque vous tapez /order
?
Commodité Les noms peuvent avoir des noms pluriels irréguliers. Parfois, ils n'en ont pas. Mais les noms singuliers sont toujours là.
par exemple. CustomerAddress over CustomerAddress
Considérez cette ressource connexe.
Ce /order/12/orderdetail/12
est plus lisible et logique que /orders/12/orderdetails/4
.
Une ressource représente une entité comme une table de base de données. Il devrait avoir un nom singulier logique. Voici le réponse sur les noms de table.
Les cours sont toujours singuliers. Les outils ORM génèrent des tables portant les mêmes noms que les noms de classes. À mesure que de plus en plus d’outils sont utilisés, les noms singuliers deviennent un standard.
En savoir plus sur A REST Le dilemme du développeur d'API
Alors que la pratique la plus répandue est celle des apis RESTful où l’on utilise des pluriels, par exemple. /api/resources/123
, il y a un cas spécial où je trouve l'utilisation d'un nom singulier plus approprié/expressif que les noms pluriels. C'est le cas des relations individuelles. Spécifiquement si l'élément cible est un objet de valeur (dans le paradigme de conception pilotée par un domaine).
Supposons que chaque ressource a un accessLog
qui peut être modélisé comme un objet de valeur, c’est-à-dire pas une entité, donc pas d’ID. Cela pourrait être exprimé par /api/resources/123/accessLog
. Les verbes habituels (POST, PUT, DELETE, GET) exprimeraient de manière appropriée l'intention ainsi que le fait que la relation est en réalité un à un.
Pourquoi ne pas suivre la tendance dominante des noms de table de base de données, où une forme singulière est généralement acceptée? Été là-bas, fait cela - réutilisons-le.
Dilemme de nommage de table: noms singulier vs noms pluriels
Je suis surpris de voir que tant de gens sautent dans le train au pluriel. Lorsque vous implémentez des conversions du singulier au pluriel, prenez-vous soin des noms pluriels irréguliers? Aimez-vous la douleur?
Voir http://web2.uvcs.uvic.ca/elc/studyzone/330/grammar/irrplu.htm
Il existe plusieurs types de pluriel irrégulier, mais ce sont les plus courants:
Type de nom Former le pluriel Exemple
Ends with -fe Change f to v then Add -s
knife knives
life lives
wife wives
Ends with -f Change f to v then Add -es
half halves
wolf wolves
loaf loaves
Ends with -o Add -es
potato potatoes
tomato tomatoes
volcano volcanoes
Ends with -us Change -us to -i
cactus cacti
nucleus nuclei
focus foci
Ends with -is Change -is to -es
analysis analyses
crisis crises
thesis theses
Ends with -on Change -on to -a
phenomenon phenomena
criterion criteria
ALL KINDS Change the vowel or Change the Word or Add a different ending
man men
foot feet
child children
person people
tooth teeth
mouse mice
Unchanging Singular and plural are the same
sheep deer fish (sometimes)
Du point de vue du consommateur d’API, les ordinateurs d'extrémité doivent être prévisibles
Idéalement...
GET /resources
devrait renvoyer une liste de ressources.GET /resource
devrait renvoyer un code d'état de niveau 400.GET /resources/id/{resourceId}
devrait renvoyer une collection avec une ressource.GET /resource/id/{resourceId}
devrait renvoyer un objet ressource.POST /resources
devrait créer des ressources par lots.POST /resource
devrait créer une ressource.PUT /resource
devrait mettre à jour un objet ressource.PATCH /resource
devrait mettre à jour une ressource en ne publiant que les attributs modifiés.PATCH /resources
devrait mettre à jour par lots les ressources affichant uniquement les attributs modifiés.DELETE /resources
devrait supprimer toutes les ressources; je plaisante: code de statut 400DELETE /resource/id/{resourceId}
Cette approche est la plus flexible et la plus riche en fonctionnalités, mais aussi la plus longue à développer. Donc, si vous êtes pressé (ce qui est toujours le cas avec le développement logiciel), il vous suffit de nommer votre point final resource
ou la forme plurielle resources
. Je préfère la forme singulière, car elle vous donne la possibilité d’effectuer une introspection et d’évaluer par programmation car toutes les formes plurielles ne se terminent pas par "s".
Cela dit, pour une raison quelconque, les concepteurs de pratiques les plus utilisés ont choisi d’utiliser le pluriel. C’est finalement la voie que j’ai choisie et si vous regardez les apis populaires comme github
et Twitter
, c’est ce qu’ils font.
Certains critères de décision pourraient être:
C'est à vous de répondre. Quoi que vous fassiez, soyez cohérent.
Je préfère utiliser la forme singulière pour la simplicité et la cohérence.
Par exemple, en considérant l'URL suivante:
/ client/1
Je traiterai le client comme une collecte de clients, mais pour des raisons de simplicité, la partie de la collection est supprimée.
Un autre exemple:
/ équipement/1
Dans ce cas, les équipements ne sont pas la forme plurielle correcte. Donc, le traiter comme une collecte d’équipements et le supprimer pour plus de simplicité le rend compatible avec le cas du client.
Mes deux cents: les méthodes qui passent du temps au pluriel au singulier ou vice-versa sont un gaspillage de cycles CPU. Je suis peut-être de la vieille école, mais à mon époque, on appelait les choses de la même façon. Comment rechercher des méthodes concernant les personnes? Aucune expression régulière ne couvrira à la fois une personne et des personnes sans effets secondaires indésirables.
Les pluriels anglais peuvent être très arbitraires et encombrent inutilement le code. S'en tenir à une convention de nommage. Les langages informatiques étaient supposés être basés sur la clarté mathématique, pas sur l’imitation du langage naturel.
Avec les conventions de dénomination, il est généralement prudent de dire "choisissez-en une et respectez-la", ce qui est logique.
Cependant, après avoir dû expliquer REST à un grand nombre de personnes, représentant les points de terminaison sous la forme chemins sur un système de fichiers, c'est la manière la plus expressive de le faire.
Il est sans état (les fichiers existent ou n’existent pas), hiérarchique, simple et familier - vous savez déjà comment accéder aux fichiers statiques, que ce soit localement ou via http.
Et dans ce contexte, les règles linguistiques ne peuvent vous amener que dans les domaines suivants:
Un répertoire peut contenir plusieurs fichiers et/ou sous-répertoires. Par conséquent, son nom doit être au pluriel.
Et j'aime ça.
Bien que, d’autre part, il s’agisse de votre répertoire, vous pouvez le nommer "une-ressource-ou-plusieurs-ressources" si vous le souhaitez. Ce n'est pas vraiment la chose importante.
Ce qui est important, c’est que si vous placez un fichier nommé "123" dans un répertoire nommé "resourceS" (résultant en /resourceS/123
), vous ne pouvez pas vous attendre à ce qu’il soit accessible via /resource/123
.
N'essayez pas de le rendre plus intelligent qu'il ne le devrait; changer de pluriel en singluier, en fonction du nombre de ressources auxquelles vous avez actuellement accès, peut paraître plaisant pour certains, mais ce n'est pas efficace et cela n'a aucun sens hiérarchique système.
Remarque: techniquement, vous pouvez créer des "liens symboliques", de sorte que /resources/123
soit également accessible via /resource/123
, mais le premier doit toujours exister!
Un identifiant dans une route doit être considéré comme un index dans une liste, et le nommage doit être poursuivi en conséquence.
numbers = [1, 2, 3]
numbers GET /numbers
numbers[1] GET /numbers/1
numbers.Push(4) POST /numbers
numbers[1] = 23 UPDATE /numbers/1
Mais certaines ressources n'utilisent pas d'identifiant dans leurs itinéraires car il n'y en a qu'un, ou un utilisateur n'a jamais accès à plus d'un, de sorte que ce ne sont pas des listes:
GET /dashboard
DELETE /session
POST /login
GET /users/{:id}/profile
UPDATE /users/{:id}/profile
Je sais que la plupart des gens sont entre décider si utiliser le pluriel ou singulier. Le problème qui n'a pas été abordé ici est que le client doit savoir lequel vous utilisez et il est toujours susceptible de se tromper. C'est de là que vient ma suggestion.
Que diriez-vous des deux? Et par là, je veux dire utiliser singulier pour toute votre API, puis créer des itinéraires pour transférer les demandes faites au pluriel au singulier. Par exemple:
GET /resources = GET /resource
GET /resources/1 = GET /resource/1
POST /resources/1 = POST /resource/1
...
Vous obtenez la photo. Personne ne se trompe, effort minimal, et le client aura toujours raison.
Au moins un aspect de l'utilisation du pluriel pour toutes les méthodes est plus pratique: si vous développez et testez une API de ressource à l'aide de Postman (ou d'un outil similaire), vous n'avez pas besoin de modifier l'URI pour passer de GET à PUT à POST etc.
Les deux représentations sont utiles. J'avais utilisé singulier pour la commodité pendant un certain temps, l'inflexion peut être difficile. Mon expérience dans le développement d'API strictement singulières REST, les développeurs utilisant le point de terminaison manquent de certitude quant à la forme du résultat. Je préfère maintenant utiliser le terme qui décrit le mieux la forme de la réponse.
Si toutes vos ressources sont de premier niveau, vous pouvez vous en tirer avec des représentations singulières. Éviter les inflexions est une grande victoire.
Si vous faites un type de lien profond pour représenter des requêtes sur des relations, alors les développeurs écrivant contre votre API peuvent être aidés par une convention plus stricte.
Ma convention est que chaque niveau de profondeur dans un URI décrit une interaction avec la ressource parent et que l'URI complet doit décrire implicitement ce qui est extrait.
Supposons que nous ayons le modèle suivant.
interface User {
<string>id;
<Friend[]>friends;
<Manager>user;
}
interface Friend {
<string>id;
<User>user;
...<<friendship specific props>>
}
Si je devais fournir une ressource permettant à un client d'obtenir le responsable d'un ami particulier d'un utilisateur particulier, cela pourrait ressembler à ceci:
GET /users/{id}/friends/{friendId}/manager
Voici quelques exemples supplémentaires:
GET /users
- liste les ressources utilisateur dans la collection globale d'utilisateursPOST /users
- crée un nouvel utilisateur dans la collection globale d'utilisateursGET /users/{id}
- récupère un utilisateur spécifique de la collection globale d'utilisateursGET /users/{id}/manager
- récupère le responsable d'un utilisateur spécifiqueGET /users/{id}/friends
- récupère la liste des amis d'un utilisateurGET /users/{id}/friends/{friendId}
- obtenir un ami spécifique d'un utilisateurLINK /users/{id}/friends
- ajoute une association d'amis à cet utilisateurUNLINK /users/{id}/friends
- supprime une association d'amis de cet utilisateurRemarquez comment chaque niveau correspond à un parent sur lequel il est possible d'agir. Utiliser des parents différents pour le même objet est contre-intuitif. Récupérer une ressource sur GET /resource/123
ne laisse aucune indication que la création d’une nouvelle ressource devrait être effectuée sur POST /resources
Que diriez-vous:
/resource/
(pas /resource
)
/resource/
signifie que c'est un dossier qui contient quelque chose appelé "ressource", c'est un dossier "resouce".
Et aussi je pense que la convention de nommage des tables de base de données est la même, par exemple, une table appelée "utilisateur" est une "table utilisateur", elle contient quelque chose appelé "utilisateur".
Google Checkout Google Guide de conception de l'API: noms de ressources pour une autre prise en charge des ressources de nommage.
En bref:
|--------------------------+---------------+-------------------+---------------+--------------|
| API Service Name | Collection ID | Resource ID | Collection ID | Resource ID |
|--------------------------+---------------+-------------------+---------------+--------------|
| //mail.googleapis.com | /users | /[email protected] | /settings | /customFrom |
| //storage.googleapis.com | /buckets | /bucket-id | /objects | /object-id |
|--------------------------+---------------+-------------------+---------------+--------------|