Reputation: 2068
Let's say I have a REST API endpoint: users/123/orders/234
.
As the URI implies, I am returning order 234 for user 123. My question is, which controller should handle the request?
Should it be an action in the UsersController, something like GetOrder(int userId, int orderId)? Or should it be handled in the OrdersController with something like GetOrder(int id)?
Is it just a matter of taste, or is one way more "correct" than the other?
Upvotes: 9
Views: 3059
Reputation: 1040
My point is to have separate controllers for these nested resources and use default action names. For example:
api/users/123/orders
- in UserOrdersController@index
That way by just looking at controller names, you know which entity the route operates on (User
in this case) and which entity is being fetched (Order
in this case)
One drawback/inconvenience for this method is that you can't use the same abstract controller as ModelController
if you have one. because index
in normal ModelController
doesn't have parameters while index
in this kind of conjunct controllers needs id
of the entity model it operates on.
Upvotes: 0
Reputation: 19465
Well I would advocate you should go by the entity that is being fetched.
In your case What is being fetched? : Orders -> So OrdersController
.
If Users were being fetched given a particular order id then it would be a UsersController
.
You should have a look at the stackexchange api for good examples : http://api.stackexchange.com/docs
There are numerous actions, but they're each grouped by the entity they operate on, and I bet that's the controller they are in.
There is no inbuilt setup for this route. You could do the following :
This is a specific route.
routes.MapHttpRoute(
name: "users_orders",
routeTemplate: "api/{controller}/{user_id}/Orders/{order_id}",
defaults: new
{
controller = "Orders",
action = "FetchByUser"
});
Which would need an action method like this:
public ActionResult FetchByUser(int user_id, int order_id)
{
}
You could try doing a more generalised route like this:
routes.MapHttpRoute(
name: "fetch_route",
routeTemplate: "api/{controller}/{id1}/{type}/{id2}",
defaults: new
{
action = "Fetch"
});
And the action method would be:
public ActionResult Fetch(int user_id, string type, int order_id)
{
}
Note: I would interpret this -> users/123/orders/234
as for the user 123 get the order 234. If like @karan says you don't need the user context then you should not have this method. I'm not sure about your design or requirements here.
Upvotes: 14
Reputation: 57949
My 2 cents. You could do something like below:
api/users/123/orders
- goes to UsersController and retrieves all orders of this particular user 123 only, where as api/orders
, which goes to the OrdersController would give all the orders in the system.
api/users/123/orders/234
- do not even support this uri space...here since user is trying to access details about the order 234, they should use api/orders/234
which should take to Orders controller.
Upvotes: 3