ASP.NET Web API get child list (hierarchical resources)

纵然是瞬间 提交于 2019-11-30 21:34:28

Routing in ASP.NET can express these more complex rules but needed to be explicitly set up. For example in this case you would have to define 2 routes:

config.Routes.MapHttpRoute(
  name: "DefaultApi",
  routeTemplate: "api/{controller}/{id}",
  defaults: new { id = RouteParameter.Optional }
);   

config.Routes.MapHttpRoute(
  name: "DefaultApi",
  routeTemplate: "api/students/{studentId}/{controller}/{classId}",
  defaults: new { classId = RouteParameter.Optional }
);   

And you would have a controller for it:

public class ClassesController
{
   public TheClass Get(int studentId, int classId)
   {
       ....
   }
}

This is perhaps not ideal but the main option.

I was working on a hierarchical routing which was not possible due to an implementation issue in Web API but this issue has been fixed now so I might start working on it again.

With this nice hierarchical approach, you have more concerns that routing internally. There is a good sample application which adopts the hierarchical resource structure: PingYourPackage. Check that out.

Note: I have a blog post about this issue which explains the below concerns and gives solutions to those with a few code samples. You can check it out for more details:

Let me explain the concerns here briefly by setting up a sample scenario. This may not be the desired approach for these type of situations but lays out the concerns very well. Let's say you have the below two affiliates inside your database for a shipment company:

  • Affiliate1 (Id: 100)
  • Affiliate2 (Id: 101)

And then assume that these affiliates has some shipments attached to them:

  • Affiliate1 (Key: 100)
    • Shipment1 (Key: 100)
    • Shipment2 (Key: 102)
    • Shipment4 (Key: 104)
  • Affiliate2 (Key: 101)
    • Shipment3 (Key: 103)
    • Shipment5 (Key: 105)

Finally, we want to have the following resource structure:

GET api/affiliates/{key}/shipments
GET api/affiliates/{key}/shipments/{shipmentKey}
POST api/affiliates/{key}/shipments
PUT api/affiliates/{key}/shipments/{shipmentKey}
DELETE api/affiliates/{key}/shipments/{shipmentKey}

Routing Concerns

@Ali already explained it but I've a different approach here. Assume that we are sending a GET request against /api/affiliates/105/shipments/102. Notice that the affiliate key is 105 here which doesn't exist. So, we would want to terminate the request here ASAP. We can achieve this with a per-route message handler.

Authorization Concerns

If you have some type of authentication in place, you would want to make sure (in our scenario here) that the authenticated user and the requested affiliate resource is related. For example, assume that Affiliate1 is authenticated under the Affiliate role and you have the AuthorizeAttribute registered to check the "Affiliate" role authorization. In this case, you will fail miserably because this means that Affiliate1 can get to the following resource: /api/affiliates/101/shipments which belongs to Affiliate2. We can eliminate this problem with a custom AuthorizeAttribute.

Ownership Concerns

Now, the following URI should get me the correct data:

GET /api/affiliates/100/shipments/102

However, what would happen for the below URI:

GET /api/affiliates/100/shipments/103

This should get you "404 Not Found" HTTP response because affiliate whose Id is 100 doesn't own the shipment whose id is 103.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!