How to pass nested parameters in REST api's for Get - c#

I have the following scenario.
There are few Events and each event is represented by group of friends.
1st i request a list of events which is achieved using simple Get request.
http://example.com:6400/api/Events/
Corresponding Rest API : public IEnumerable<Event> Get();
Now i can search the event list and can request for a particular event say (event 5)
http://example.com:6400/api/Events/eventdetail/5.
Corresponding Rest API : public HttpResponseMesssage eventdetail(int id);
But now if i want to receive info about a particular friend(say friend's id is 10) in that event(5) i am unable to find a way. One way i was able to achieve is using a comma separated
Get request:
http://example.com:6400/api/Events/eventdetail/5,10.
Corresponding Rest API: Not Sure ????
But i don't think this is the best way to do it. Is there any ways through which i can achieve the desired result and corresponding Rest API.

Just start accepting two parameters in your method:
public HttpResponseMesssage EventDetail(int id, int friendId) {
//Do your stuff!
}
The corresponding URI would look like:
http://example.com:6400/api/Events/EventDetail/5?friendId=10
Notice how the HTTP parameter name matches the C# method name. For more information about ASP.NET MVC routing I would suggest reading their overview.

Related

How to configure swagger to make complex [FromUri] GET parameters show up nicely in Swagger

I've been trying to figure this out for about a week now. It's time to ask S.O.
I have 4 overall goals here:
The controller code needs to use ViewModel request inputs for validation reasons. (Controller Snippet)
Client code for my API should use a nice model syntax. (Client Code Snippet)
For the swagger UI page, I would like the "Try me" interface to be usable. Either a bunch of text boxes, or a text area for a json blob to serialize and send over.
GET request
Client Code Snippet:
var response = client.GetUserProductHistory(new Models.UserProductHistoryRequest() {
Locale = "en-US",
UserPuid = "FooBar"
});
Controller Snippet
[HttpGet]
[HasPermission(Permissions.CanViewUserProductHistory)]
public JsonPayload<UserProductHistoryResponse> GetUserProductHistory([FromUri]UserProductHistoryRequest model)
{
JsonPayload<UserProductHistoryResponse> output = new JsonPayload<UserProductHistoryResponse>();
return output;
}
I have tried using [FromBody]. It looks great, but I get an error that says 'GET requests do not support FromBody'.
I tried using [FromUri], but then the generated client gives me like 15 method parameters per call in the generated client.
I tried using [FromUri], and operation filters so that the parameters would be condensed into Ref parameters (complex objects as defined by the spec). This actually worked decently for the client generation and the server side. Problem is, the UI for swagger looks really lame. A single TEXT box that you can't actually use very well. If I can figure out how to get the Swagger UI to change the appearance of the [FromUri] request to more closely match the [FromBody] UI, I will be in good shape here. Any ideas or pre-existing content that would point me in the right direction here?
Swagger is not the limitation - REST itself is. By definition of REST, web servers should ignore the incoming request body on all HTTP GET methods. ASP.NET enforces this convention, which is why you it doesn't allow you to use [FromBody] on the GET method.
When designing a REST API, the better practice is to use POST methods for an actual search. This will allow to use [FromBody], and as a bonus, Swagger will behave the way you want it to. See here for a supporting opinion: https://stackoverflow.com/a/18933902/66101

RESTful Way to Handle Updating Detail Records

If I need to update many detail rows, my Web API controller method might look like this, using an RPC style:
[Route("api/updateAccountDetailStatus")]
[HttpGet]
public IHttpActionResult UpdateAccountDetailStatus(int accountId, string status)
That would change all of the detail rows, associated with that account, to the new status.
In trying to take a RESTful approach, my guess is that it would be something like this:
PATCH /accounts/110
{
"status": "hold"
}
[Route("api/accounts/id")]
[HttpGet]
public IHttpActionResult Account(Account account)
What I don't like about that is now the API controller method needs to interrogate the object to see how to handle it. In this case, it would be changing all of the detail rows to that new status. But what if someone calls that patch and sends a different property to modify? Now I have to change behavior based on that? Is there a better way?
I see the conundrum. On one hand, you would like to stay true and not have action names (change, update, etc) in your URI, and on the other hand, this is a special procedure and not quite a PATCH really.
So, for this article I did some work to allow the action to be defined by the type of the message sent, even created a means of doing that in Web API.
The sample code for this is here.
Essentially you expose these as POST or PUT (depending on whether they are idempotent or not) and the resource will have multiple POST or PUT against it. For Example:
GET /api/InventoryItem [gets all items]
GET /api/InventoryItem/{id} [gets detail of a single item]
POST /api/InventoryItem [creates an item]
POST /api/InventoryItem/{id}* [checks in stock items to the inventory]
POST /api/InventoryItem/{id}* [removes stock items from the inventory]
PUT /api/InventoryItem/{id} [renames an item]
DELETE /api/InventoryItem/{id} [de-activates an item]
This is the only solution I have had so far for these types of resources.
UDPATE
Essential you would expose this as PUT (since I imagine it is idempotent) at api/accounts/id sending a payload signifying type of the message:
PUT api/accounts/id
{"detailBatchStateChange": "hold"}

web api 2 routing with version and route attributes

Within my project I have 2 versions of an API. From this Post I understand that a custom control selector needs writing so it get get the different versions (as webapi looks for controller name match and ignores the namespaces they are in).
This all works OK and I can make the calls to the different versions.
However, I also utilise the new data attribute routing from web api 2 and when using this the customer control selector does not handle the routing correctly.
The routing data attributes I am using are as follows.
(The V01 differs between the versions so it can be V02)
[Route("api/v01/enumeration/{type}/{subtype}")]
This can contain some additional query string params at the end as well
[Route("api/V01/user/readbyreference")]
this takes a query string of ?id=EMAIL|email.domain.com
The code for the customer control selector can be found here
I can see the issue is with GetRouteVariable to get the needed namespace part and controller, but I was wondering if anyone else has had to do something like this and if they have any way around it.
I will be looking into so if I find something I will update on here but if you have anything please let me know.
Thanks
Mark
After a bit of digging I have found out that attribute routing goes via a different path.
So to handle attribute routing in the GetRouteVariable you need to grab the MS_SubRoutes values and then perform the needed action on the result to get the namespace and controller.
The below needs tidying up but it at least gives you the idea of what is done to process data attribute routing in your custom control selector
var subroutes = (IEnumerable<IHttpRouteData>)routeData.Values["MS_SubRoutes"];
var routeBreakDown= subroutes.First().Route.RouteTemplate.Split('/');
if (name == "namespace")
{
return (T)(object)routeBreakDown[1]; //namespace
}
else if (name == "controller")
{
return (T)(object)routeBreakDown[2]; //controller
}
Cheers
Mark

REST API different resources for GET and POST/PUT?

I'm currently in the process of designing as RESTful of an API as I can using Microsoft's Web API 2 in C#. What I'm struggling on is how best to represent resources or the proper way to do it where the GET call and POST/PUT are very different.
For example say I have something calls states that have an id, name, status, etc., these can be assigned to a document. So I have a route like this /documents/{id}/states/ . If I call a GET here I need to get the full list of all assigned states including their id, name, etc.
However, in order to change which states are assigned to the document I simply need to pass the id. I cannot do this individually, it must be an array that gets sent up since users may be interacting with hundreds or thousands at a time.
So in this case I have a few issues. I don't even know if POST or PUT is correct here, and second whichever one it is can I just take in an array of integers?
In your case, I would suggest PUT is the method you would be wanting to use, as you know the location of the resource that you are updating. For more info, see here: http://restcookbook.com/HTTP%20Methods/put-vs-post/
In ASP.NET Web API 2 you can use the [FromBody] parameter attribute, so that your method signature would be:
public void UpdateStates(int id, [FromBody]List<int> states) {}
More info on parameter attributes can be found here: http://www.asp.net/web-api/overview/formats-and-model-binding/parameter-binding-in-aspnet-web-api

Get operation name in Message Inspector?

Im using the IClientMessageInspector to log in/out messages but the problem is that I canĀ“t find how to get the operation name from AfterReceivedReply and BeforeSendRequest.
I have tested the following :
if ((action = reply.Headers.Action.Split('/').LastOrDefault()) != null)
{
callInformation.Action = action;
callInformation.Address = reply.Headers.Action.Replace(action, "");
}
This works fine in BeforeSendRequest but in the AfterReveivedReply it returns something different, often with the "Response" on the end?
How do I only get the operation name in those methods?
Say, that my operation is named MyOperation and a OperationContract attribute states the action = "MyOpeation" (wrong spelling). This result of this is that MyOpeation will be extracted in BeforeSendRequest while the AfterReceiveReply will return MyOperationResponse.
So the BeforeSendRequest will extract the stated action in the attribute and the AfterReceiveReply will extract the real operation name but with the add of "Response" on the end?
Its important to be able to match the in/out messages and the only way of doing this as I see it is to match the operation names but if that is not possible then I do not see a good solution to this?
I have seen solution when using OperationContext.Current.IncomingMessageHeaders.Action but the OperationContect.Current is null when doing this on the client side.
From your question I assume you want to match In/Out messages by any means - the framework provides for this:
In the implementation of IClientMessageInspector.BeforeSendRequest you can return a unique correlationState which in turn allows you to relate the reply message in your implementation of IClientMessageInspector.AfterReceiveReply since the Framework will call your implementation with it as the second parameter.
EDIT - as per comments below:
IF you really need to get the name of the operation/method called you could do this is by implementing IClientMessageFormatter.SerializeRequest OR IParameterInspector - this will allow you to to record which method with which parameters have been called and what Message object the framework created for it.

Categories

Resources