EDIT : Bien que cette réponse soit toujours valable pour l'API Web 1, pour l'API Web 2, je conseille vivement d'utiliser La réponse de Daniel Halan car il s'agit de l'état de l'art pour le mappage des sous-ressources (entre autres subtilités).
Certaines personnes n'aiment pas utiliser {action} dans les API Web parce qu'elles pensent que, ce faisant, elles brisent l'"idéologie" REST... Je soutiens que. {action} est simplement une construction qui aide au routage. Elle est interne à votre implémentation et n'a rien à voir avec le verbe HTTP utilisé pour accéder à un fichier ressource .
Si vous imposez des contraintes de verbe HTTP aux actions et que vous les nommez en conséquence, vous n'enfreignez aucune directive RESTful et vous vous retrouverez avec des contrôleurs plus simples et plus concis au lieu de tonnes de contrôleurs individuels pour chaque sous-ressource. N'oubliez pas : l'action n'est qu'un mécanisme de routage, et elle est interne à votre mise en œuvre. Si vous vous heurtez au framework, c'est que quelque chose ne va pas, soit avec le framework, soit avec votre implémentation. Il suffit de mapper l'itinéraire avec une contrainte HTTPMETHOD pour que tout aille bien :
routes.MapHttpRoute(
name: "OneLevelNested",
routeTemplate: "api/customers/{customerId}/orders/{orderId}",
constraints: new { httpMethod = new HttpMethodConstraint(new string[] { "GET" }) },
defaults: new { controller = "Customers", action = "GetOrders", orderId = RouteParameter.Optional, }
);
Vous pouvez les gérer dans le CustomersController de la manière suivante :
public class CustomersController
{
// ...
public IEnumerable<Order> GetOrders(long customerId)
{
// returns all orders for customerId!
}
public Order GetOrders(long customerId, long orderId)
{
// return the single order identified by orderId for the customerId supplied
}
// ...
}
Vous pouvez également acheminer une action Créer sur la même "ressource" (commandes) :
routes.MapHttpRoute(
name: "OneLevelNested",
routeTemplate: "api/customers/{customerId}/orders",
constraints: new { httpMethod = new HttpMethodConstraint(new string[] { "POST" }) },
defaults: new { controller = "Customers", action = "CreateOrder", }
);
Et le traiter en conséquence dans le contrôleur du client :
public class CustomersController
{
// ...
public Order CreateOrder(long customerId)
{
// create and return the order just created (with the new order id)
}
// ...
}
Oui, vous devez toujours créer beaucoup de routes, car l'API Web ne peut toujours pas diriger vers différentes méthodes en fonction du chemin... Mais je pense qu'il est plus propre de définir les routes de manière déclarative que d'inventer des mécanismes de répartition personnalisés basés sur des enums ou d'autres astuces.
Pour le consommateur de votre API, cela aura l'air parfaitement RESTful :
GET http://your.api/customers/1/orders
(correspond à GetOrders(long) qui renvoie toutes les commandes du client 1)
GET http://your.api/customers/1/orders/22
(correspond à GetOrders(long, long) qui renvoie la commande 22 du client 1)
POST http://your.api/customers/1/orders
(correspond à CreateOrder(long) qui créera un ordre et le retournera à l'appelant (avec le nouvel ID qui vient d'être créé).
Mais ne prenez pas ma parole comme une vérité absolue. Je suis encore en train de l'expérimenter et je pense que MS n'a pas réussi à traiter correctement l'accès aux sous-ressources.
Je vous invite à essayer http://www.servicestack.net/ pour une expérience moins douloureuse d'écriture d'apis REST... Mais ne vous méprenez pas, j'adore les API Web et je les utilise pour la plupart de mes projets professionnels, principalement parce qu'il est plus facile de trouver des programmeurs qui les "connaissent" déjà... Pour mes projets personnels, je préfère ServiceStack.