I can advise that you are not using REST correctly. There is a good answer on how to best structure your ServiceStack REST service . This is a common startup problem, I also had such problems.
Understanding your use case:
In your specific case, if we look at /orders/customers/7 , this will work better, you think of it as follows:
/ customers / 7 / Orders
The reason you do this:
- It fixes route ambiguity problems.
- The context is clear. We see that we are working with Customer 7 without navigating a long URL
- We can see "with customer 7", we want their orders
Think of routing as follows:
/orders Everybody Orders /orders/1 Order 1 (without being aware of the customer it belongs to) /customers All Customers /customers/7 Customer 7 details /customers/7/orders All Customer 7 orders /customers/7/orders/3 Customer 7 order number 3
The beauty of doing such things is data operations that are performed sequentially. So you want to find all canceled orders:
/orders/cancelled
You want to cancel its specific orderId order
/orders/4/cancel
Do you want to specify specific customer orders
/customers/6/orders/open
You want to display sales order 6 canceled orders
/customers/6/orders/cancelled
You want to cancel the order for customer 6 you are viewing
/customers/6/orders/2/cancel
Obviously these are just scenarios, your routes will be different.
Simplification of action handlers:
You probably want to define your action handlers so that they can handle multiple routes. I mean that one handler will be responsible for listing orders
/orders /customers/6/orders
What am I doing:
[Route("/orders","GET")] [Route("/customers/{CustomerId}/orders","GET")] public class ListOrdersRequest : IReturn<List<Order>> { public int? CustomerId { get; set; } }
So, you can see how the two routes of the order list go. If they use /orders , then our customerId will not matter, and there will be another route. Therefore, in our action handler, we can simply verify this:
public List<Order> Get(ListOrdersRequest request) {
Customer side questions:
So, to address your "typed" customer needs. Creating routes and action handlers using the above method will allow you to:
client.Get(new ListOrdersRequest { CustomerId = 7 });
Thus, you will get 1 clear method for listing orders.
Final thoughts:
Obviously, this means that you have to rework what you have, which is likely to be a pain, but this is the best approach, well worth the effort.
Hope this helps you understand a better structure.
Update:
@ stefan2410 asked me to address the issue of using Kyle int[] in the route for a GET request:
If you want to use int[] in a GET request, you need to consider changing it during transport in the URL so that it can be used RESTfully.
So you can do this:
class OrdersRequest { public string Ids { get; set; } public OrdersRequest(int[] ids) { Ids = string.Join(",", Array.ConvertAll(ints, item => item.ToString())); } } client.Get(new OrdersRequest(new [] {1,2,3}));
Creates the route /orders/1,2,3 and matches /orders/{Ids} . The problem with this is to use server-side identifiers, you need to convert the string "1,2,3" back to int[] .
The best way to handle int[] in a request is to use POST. So you can do:
class OrdersRequest { public int[] Ids { get; set; } public OrdersRequest(int[] ids) { Ids = ids; } } client.Post(new OrdersRequest(new[] {1,2,3}));
Creates a route /orders and matches the route /orders .