Recently, it has been hard to find out whether to create restful APIs or those previously called functions. If you create a restful API, there are many design issues to be clarified. This is not a matter of time. When you use a web API to create a restful API, how can I design an API for second-level entity Operations? For example, a client object has many order entities belonging to it, and each order entity has many product entities. How can I design an API interface to better reflect this relationship and operation? If you have any idea about this, please leave a message to help me solve the problem.
I am trying to design and implement a hierarchical API. I'm not sure if this is the best practice. It looks like this when calling:
/API/clients/123/orders/456/products/789
Route looks like this:
/API/{controller}/{ID}/{subcontroller1}/{subid1}/{subcontroller2}/{subid2}
Of course, if necessary, you can continue to append subcontroller3, 4,5, 6...
What does the Controller look like? My approach is to create a controller for the client, order, and product respectively:
Clientscontroller
Clientsorderscontroller
Clientsordersproductsconroller
In this way, I can map the names of the above three controllers to {controller}, {subcontroller1}, and {subcontroller2}. Abstract, it is one of {controller}/{subcontrollerx} corresponding to each part of the controller name }.
The remaining question is how to allow the MVC engine to map this route to the correct controller. We all know (we don't actually know, including me before studying this issue) that the MVC engine depends on the ihttpcontrollerselector interface to find controller operations based on routing, by default, the defaulthttpcontrollerselector class is used to inherit the class and check whether the subcontroller parameters are mapped to specific data from the route data. If not, call the default action. If yes, concatenate the values of all controller parameters into a real controller name,CodeAs follows:
1 Using System; 2 Using System. Collections. Generic; 3 Using System. LINQ; 4 Using System. Web. HTTP; 5 Using System. Web. http. Dispatcher; 6 Using System. net. HTTP; 7 Using System. Web. http. Routing; 8 9 Namespace Ricky 10 { 11 Public Class Httpcontrollerselectorex: defaulthttpcontrollerselector 12 { 13 Private Httpconfiguration _ httpcfg; 14 15 Public Httpcontrollerselectorex (httpconfiguration CFG) 16 : Base (CFG) 17 { 18 _ Httpcfg = CFG; 19 } 20 21 Public Override String Getcontrollername (httprequestmessage request) 22 { 23 String Name = Base . Getcontrollername (request ); 24 Ihttproutedata routedata = Request. getroutedata (); 25 Ienumerable <keyvaluepair < String , Object > Subcontrollers = Routedata. Values 26 . Where (D => D. Key. startswith ( " Subcontroller " , Stringcomparison. currentcultureignorecase )); 27 If (Subcontrollers. Count () = 0 ) 28 Return Name; 29 30 List < String > Names = New List < String > (1 + Subcontrollers. Count ()); 31 Names. Add (name ); 32 Foreach (Keyvaluepair < String , Object > Subcontroller In Subcontrollers) 33 { 34 Names. Add (subcontroller. value. tostring ()); 35 } 36 37 Return String . Join ( "" , Names ); 38 } 39 } 40 }
After that, use our controller selector to replace the default settings of the system. This is done in the application_start method of Global. asax. CS:
1Globalconfiguration. configuration. Services. Replace (Typeof(Ihttpcontrollerselector)2,NewRicky. httpcontrollerselectorex (globalconfiguration. configuration ));
Finally, let's modify the route settings:
1 Public Static Void Register (httpconfiguration config) 2 { 3 Config. routes. maphttproute ( 4 Name: " Defaultapiwithsubcontrollers " , 5 Routetemplate: " API/{controller}/{ID}/{subcontroller}/{subid}/{subcontroller2}/{subid2} " , 6 Defaults: New 7 { 8 Id = Routeparameter. Optional, 9 Subcontroller = Routeparameter. Optional, 10 Subid = Routeparameter. Optional, 11 Subcontroller2 = Routeparameter. Optional, 12 Subid2 = Routeparameter. Optional 13 } 14 ); 15 16 // Config. routes. maphttproute ( 17 // Name: "defaultapi ", 18 // Routetemplate: "API/{controller}/{ID }", 19 // Defaults: New {id = routeparameter. optional} 20 // ); 21 }
Because our route settings actually extend the default settings, you can comment out the original default settings.