Autant que je sache, chaque ressource individuelle ne devrait avoir qu'un seul chemin canonique . Dans l'exemple suivant, quels seraient les bons modèles d'URL?
Prenons par exemple une représentation représentative des entreprises. Dans cet exemple hypothétique, chaque entreprise possède 0 ou plusieurs départements et chaque département possède 0 ou plusieurs employés.
Un département ne peut exister sans une entreprise associée.
Un employé ne peut exister sans un service associé.
Maintenant, je trouverais la représentation naturelle des modèles de ressources.
/companies
Une collection d'entreprises - Accepte une nouvelle entreprise. Obtenez pour toute la collection./companies/{companyId}
Une entreprise individuelle. Accepte GET, PUT et DELETE/companies/{companyId}/departments
Accepte le POST pour un nouvel élément. (Crée un département au sein de l'entreprise.)/companies/{companyId}/departments/{departmentId}/
/companies/{companyId}/departments/{departmentId}/employees
/companies/{companyId}/departments/{departmentId}/employees/{empId}
Compte tenu des contraintes, dans chacune des sections, je pense que cela a du sens s'il est un peu profondément imbriqué.
Cependant, ma difficulté vient si je veux lister ( GET
) tous les employés dans toutes les entreprises.
Le modèle de ressources correspondant le plus étroitement à /employees
(La collection de tous les employés)
Cela signifie-t-il que j'aurais dû /employees/{empId}
aussi parce que si c'est le cas, il y a deux URI pour obtenir la même ressource?
Ou peut-être que le schéma entier devrait être aplati, mais cela signifierait que les employés sont un objet de niveau supérieur imbriqué.
Au niveau de base, /employees/?company={companyId}&department={deptId}
la même vue des employés est exactement la même que le modèle le plus profondément imbriqué.
Quelle est la meilleure pratique pour les modèles d'URL dans lesquels les ressources appartiennent à d'autres ressources mais doivent être interrogeables séparément?
la source
Réponses:
Ce que vous avez fait est correct. En général, il peut y avoir plusieurs URI vers la même ressource - il n'y a pas de règles qui disent que vous ne devriez pas faire ça.
Et généralement, vous devrez peut-être accéder aux éléments directement ou en tant que sous-ensemble de quelque chose d'autre - donc votre structure est logique pour moi.
Tout simplement parce que les employés sont accessibles par département:
company/{companyid}/department/{departmentid}/employees
Cela ne veut pas dire qu'ils ne peuvent pas non plus être accessibles sous l'entreprise:
company/{companyid}/employees
Ce qui rendrait des employés pour cette entreprise. Cela dépend de ce dont votre client consommateur a besoin - c'est pour cela que vous devriez concevoir.
Mais j'espère que tous les gestionnaires d'URL utilisent le même code de support pour satisfaire les demandes afin que vous ne dupliquiez pas le code.
la source
/company/3/department/2/employees/1
). Si l'API fournit des moyens d'obtenir chaque ressource, alors chacune de ces demandes peut être effectuée dans une bibliothèque côté client ou en tant que point de terminaison unique qui réutilise le code./company/*
ne doit renvoyer que la ressource de l'entreprise et ne pas modifier du tout le type de ressource. Rien de tout cela n'est spécifié par REST - c'est généralement une préférence mal spécifiée - juste une préférence personnelle.J'ai essayé les deux stratégies de conception - points de terminaison imbriqués et non imbriqués. J'ai trouvé que:
si la ressource imbriquée a une clé primaire et que vous n'avez pas sa clé primaire parent, la structure imbriquée vous oblige à l'obtenir, même si le système n'en a pas réellement besoin.
les points de terminaison imbriqués nécessitent généralement des points de terminaison redondants. En d'autres termes, vous aurez le plus souvent besoin du point de terminaison supplémentaire / employés pour pouvoir obtenir une liste des employés dans les différents services. Si vous avez / employés, qu'est-ce que / entreprises / services / employés vous achètent exactement?
les points de terminaison d'imbrication n'évoluent pas aussi bien. Par exemple, vous n'aurez peut-être pas besoin de rechercher des employés maintenant, mais vous pourrez le faire plus tard et si vous avez une structure imbriquée, vous n'avez pas d'autre choix que d'ajouter un autre point de terminaison. Avec une conception non imbriquée, vous ajoutez simplement plus de paramètres, ce qui est plus simple.
Parfois, une ressource peut avoir plusieurs types de parents. Il en résulte plusieurs points de terminaison renvoyant tous la même ressource.
les points de terminaison redondants rendent les documents plus difficiles à écrire et rendent également l'API plus difficile à apprendre.
En bref, la conception non imbriquée semble permettre un schéma de point de terminaison plus flexible et plus simple.
la source
J'ai déplacé ce que j'ai fait de la question à une réponse où plus de gens sont susceptibles de le voir.
Ce que j'ai fait, c'est d'avoir les points de terminaison de création sur le point de terminaison imbriqué. Le point de terminaison canonique pour modifier ou interroger un élément n'est pas sur la ressource imbriquée .
Donc, dans cet exemple (énumérant simplement les points de terminaison qui modifient une ressource)
POST
/companies/
crée une nouvelle société renvoie un lien vers la société créée.POST
/companies/{companyId}/departments
lorsqu'un département est créé crée le nouveau département renvoie un lien vers/departments/{departmentId}
PUT
/departments/{departmentId}
modifie un départementPOST
/departments/{deparmentId}/employees
crée un nouvel employé renvoie un lien vers/employees/{employeeId}
Il existe donc des ressources de niveau racine pour chacune des collections. Cependant, la création se trouve dans l' objet propriétaire .
la source
POST
sensPUT
, et autrement.J'ai lu toutes les réponses ci-dessus, mais il semble qu'ils n'aient pas de stratégie commune. J'ai trouvé un bon article sur les meilleures pratiques de Design API de Microsoft Documents . Je pense que vous devriez vous référer.
.
la source
L'aspect de vos URL n'a rien à voir avec REST. Tout va. Il s'agit en fait d'un "détail d'implémentation". Donc, tout comme la façon dont vous nommez vos variables. Tout ce qu'ils doivent être est unique et durable.
Ne perdez pas trop de temps à ce sujet, faites simplement un choix et respectez-le / soyez cohérent. Par exemple, si vous optez pour des hiérarchies, vous le faites pour toutes vos ressources. Si vous allez avec des paramètres de requête ... etc, tout comme les conventions de dénomination dans votre code.
Pourquoi Pour autant que je sache, une API "RESTful" doit être consultable (vous savez ... "Hypermedia en tant que moteur de l'état de l'application"), donc un client API ne se soucie pas de ce que sont vos URL tant qu'elles sont valide (il n'y a pas de référencement, pas d'humain qui a besoin de lire ces "URL amicales", sauf peut-être pour le débogage ...)
Le caractère agréable / compréhensible d'une URL dans une API REST ne vous intéresse qu'en tant que développeur d'API, pas en tant que client d'API, comme le serait le nom d'une variable dans votre code.
La chose la plus importante est que votre client API sache comment interpréter votre type de média. Par exemple, il sait que:
Voici un exemple d'échange HTTP (les corps sont en yaml car il est plus facile d'écrire):
Demande
Réponse: une liste de liens vers la ressource principale (entreprises, personnes, peu importe ...)
Demande: lien vers les entreprises (en utilisant la réponse précédente body.links.companies)
Réponse: une liste partielle des sociétés (sous les éléments), la ressource contient des liens connexes, comme un lien pour obtenir les deux sociétés suivantes (body.links.next), un autre lien (basé sur un modèle) pour rechercher (body.links.search)
Donc, comme vous le voyez, si vous suivez les liens / relations, la façon dont vous structurez la partie chemin de vos URL n'a aucune valeur pour votre client API. Et si vous communiquez la structure de vos URL à votre client en tant que documentation, alors vous ne faites pas REST (ou du moins pas le niveau 3 selon le " modèle de maturité de Richardson ")
la source
Je suis en désaccord avec ce genre de chemin
Si vous voulez obtenir des départements, je pense qu'il vaut mieux utiliser une ressource / départements
Je suppose que vous avez une
companies
table et unedepartments
table puis des classes pour les mapper dans le langage de programmation que vous utilisez. Je suppose également que les départements peuvent être attachés à d'autres entités que les entreprises, donc une ressource / départements est simple, il est pratique d'avoir des ressources mappées sur des tables et vous n'avez pas besoin d'autant de points finaux car vous pouvez réutiliserpour tout type de recherche, par exemple
Si vous souhaitez créer un service, le
la ressource doit être utilisée et le corps de la demande doit contenir l'ID de l'entreprise (si le service ne peut être lié qu'à une seule entreprise).
la source
GET /companies/{companyId}?include=departments
, car cela permet à la fois à la société et à ses services d'être récupérés dans une seule requête HTTP. Fractal fait ça très bien./departments
point de terminaison pour qu'il ne soit accessible que par un administrateur, et que chaque entreprise n'accède à ses propres services que via `/ companies / {companyId} / départements`Rails apporte une solution à ce problème: l' emboîtement peu profond .
Je pense que c'est une bonne chose car lorsque vous traitez directement avec une ressource connue, il n'est pas nécessaire d'utiliser des routes imbriquées, comme cela a été discuté dans d'autres réponses ici.
la source