REST API different resources for GET and POST/PUT? - c#

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

Related

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"}

Using POST or GET for a WebAPI Action method that returns a list, but requires params

Currently I have the following standard functions in each of my controllers to handle basic CRUD operations:
GET /api/todo Get all to-do items
GET /api/todo/{id} Get an item by ID
POST /api/todo Add a new item
PUT /api/todo/{id} Update an existing item
DELETE /api/todo/{id} Delete an item
However, the time came where I realized I actually need to pass multiple parameters to get a list of todo items that is filtered at the database level rather than retrieving all of the items and using linq.
For example here is how I decided to go about it:
In my Controller:
// POST: api/todo
[HttpPost]
public IList<TodoItem> Get([FromBody]GetTodoItemsRequest request)
{
return _todoItemManager.GetTodoItems(request.Name, request.CategoryId);
}
As you can see I created a new Model called GetTodoItemsRequest which will have a property for each of my parameters. In this case: Name, CategoryId.
I figured when dealing with multiple parameters and retrieving a list it is best to do POST and create a model specifically for it. Rather than using a GET and passing all kinds of information in the url.
It seems a bit strange to be doing the above... Would msot see it as a perfectly fine solution or is there something I am missing in the WebAPI world?
I believe that is semantically incorrect to use POST method for a simple read operation, even if you need a complex model. You are doing a pure query on your resource called todo, and this should really be a GET operation for many reasons:
It should be cachable: POST request aren't cachable by their nature, and caching is an important constraint in RESTful services.
It should semantically indicate that no side-effect will be raised from the call: GET requests must be idempotent and safe, POST operations, instead, indicate some kind of data manipulation. Your operation (filtering) is both idempotent and safe, so it should be spontaneously represented by a GET request.
The part of the URI after a ? character is called query string for a reason: it represent parameters that further specify the scope of a request. Well, isn't filtering results just an example of this approach?
Apart from that, it seems to me that, if Name and CategoryId are required parameters for your query, your filtering operation could be better represented by another URI in which Name and CategoryId are turned into route parameters:
http://yourhost.com/api/users/{name}/categories/{categoryId}/todos
Assuming a relationship between your name parameter (a user name maybe?) and the categories.
If, instead, your parameters are completely optional, then leaving them as query string parameters is the best choice:
http://yourhost.com/api/todos?name=nameValue&categoryId=categoryIdValue
A side note:
you should really use plural for your resources if they represents a collection of items: e.g. api/todo will return an array of todos, so you should rename it into api/todos.

Is it possible to get a list of all values that can be returned in a web service

Is it possible to get a list of all values that can be returned in a web service?
I am looking at APIs from Open Weather Map doing these 2 calls:
http://api.openweathermap.org/data/2.5/weather?q=paarl
http://api.openweathermap.org/data/2.5/weather?q=London,uk
If you look at the JSON returned you will see that for Paarl there are extra properties in main like grnd_level and sea_level that London doesn't return.
Is it possitbly for me to see all that values that can be returned and not just the values that are returned. Maybe I search for another region and then it returns other values that I am not aware of. I can't always go and check the JSON results.
I would like to cater for most/almost all scenarios.
API does not provide exact props, so it might be different for cities and be based on station too. As for me, you should choose properties you wanna see in your program and display them, no need to show all the possible data.

How to Design a Restful API for Bulk Inserts and Updates?

I have a Web API application and I'm using the below url for both bulk (tens or hundreds) inserts and updates which return just OK or Failed.
POST api/v1/products
which is mapped to my action:
public HttpResponseMessage PostProducts(PostProductsRequest request)
{
...
}
PostProductsRequest object contains a Products property of type List.
If the Id property exists for a Property, I update it otherwise it'd indicate an insert.
But I'm just wondering whether I should use Post for Bulk Inserts only and Put for Bulk Updates, not sure. What's the best practice and advantage of each approach?
How to Design a Restful API for Bulk Inserts and Updates?
Either method can be used, depending on your requisites, but this doesn't mean they don't have significant differences. HTTP methods are not CRUD. PUT or POST are not Create and Update, or the other way around.
PUT completely replaces the resource at the given URI with the entity provided, so it can be used to create and also to update, but only if it contains the full representation. A GET request made immediately after a PUT should return the same resource. The representation may be exactly the same, although it's possible for the service to add default values that were missing from the PUT'ed representation.
POST tells the server that the entity being provided is subordinated to the resource at the given URI, and they have an agreement on what it should be done with that. It might be anything, a create, an update, any operation that isn't standardized by HTTP itself.
With this in mind, a bulk insert or update with PUT is only RESTful if you're replacing the whole collection identified by the URI. This doesn't have to be necessarily your whole collection associated with that media type. The URI can have a querystring slicing the dataset, and you perform the bulk operation on that slice only.
For instance, if you have the following collection resource:
GET /api/products
Represented by:
{'products': [product1, product2, product3]}
And you want to add three more products, a bulk operation with PUT would have to append your new products to the existent and send the whole collection back:
PUT /api/products
{'products': [product1, product2, product3, product4, product5, product6]}
However, if you have a filter constraint you can apply to /api/products that would return an empty collection on the GET above, then it would be fine to do the PUT only with the new products to that filtered resource. For instance, let's say the products above can be filtered by a partner attribute, they have partner x and you're adding for partner y:
In that case, it's fine for you to do:
PUT /api/products?partner=y
{'products': [product4, product5, product6]}
And a GET /api/products after that returns:
{'products': [product1, product2, product3, product4, product5, product6]}
As long as GET /api/products?partner=x returns:
{'products': [product1, product2, product3]}
And GET /api/products?partner=y returns:
{'products': [product4, product5, product6]}
This might seem complicated and sometimes it looks like it's better to use POST instead of PUT, but keep in mind that the whole operation above is standardized. It's using PUT exactly as it's intended to be used. The operations can be more straightforward with POST, but they are not standardized and you'll have to design and document your own syntax for it.
I would recommend to use POST to create and PUT to update (actually create or update as it is indempotent).
From the RESTful Webservices Cookbook (O'Reilly):
Use POST and a collection resource to create a number of similar resources at once.
Let
clients include information about the resources to be created in the request. Assign a
URI for all the resources created, and redirect the client to the collection using response
code 303 (See Other). A representation of this resource includes links to all the newly
created resources.
To update or delete a number of similar resources in bulk, use a single URI that can
return a representation containing information about all those resources. Submit a
PUT request to that URI with information about the resources to be updated or a
DELETE request to delete those resources.
In all these cases, ensure that the processing of the request is atomic.
I just happened to be looking at the HTTP 1.1 method definition and was reminded of this question.
The PUT method requests that the enclosed entity be stored under the supplied Request-URI. If the Request-URI refers to an already existing resource, the enclosed entity SHOULD be considered as a modified version of the one residing on the origin server. If the Request-URI does not point to an existing resource, and that URI is capable of being defined as a new resource by the requesting user agent, the origin server can create the resource with that URI.
This would indicate to me that if you were to use PUT and the payload contained a not existing resource with enough information to create it then it should be created and therefore PUT would be the correct method verb in a bulk operation that can create & update resources.
The most "standards compliant" way for batch operations in RESTful Web services is to use one of the various 'collection' approaches (i.e. DELETE /mail?&id=0&id=1&id=2) or you could use a batching handler to simply the process.
Honestly, I use the exact same pattern as you do except for the fact that I use POST for object creation and PUT for updates only (which is the standard way of doing it). Also POST should return 201 - Created along with the created object and PUT should return 204 - No Content with no data, if the operation succeeds. Of course, as you're doing bulk creation, you may opt not to return the array of newly created objects with POST.
To summarize it:
POST api/products
|
|---> Success: 201 [NewObject1, NewObject2, ...]
|---> Failure: Relevant error code as to why the operation failed
PUT api/products
|
|---> Success: 204
|---> Failure: Relevant error code as to why the operation failed
Update: vNext of ASP.NET Web API will have batching built in!

What use is initUserDefaultOptionalParameterPackage in EWL?

I'm using EWL and I have an EwfPage and when I type partial in the Info class I see:
partial void initDefaultOptionalParameterPackage( OptionalParameterPackage package )
and
partial void initUserDefaultOptionalParameterPackage( OptionalParameterPackage package )
I don't really see what they're used for. They also sound similar and I'm wondernig what the difference between them is.
They are both used if you want an optional parameter to default to something other than the default value of its C# data type. There are two significant differences:
initUserDefaultOptionalParameterPackage is called only when you are creating an Info object for the page; it is not called when the page is requested. If a request is made without a parameter value in the URL, the framework will fall back to the value specified in initDefaultOptionalParameterPackage or the data type default.
You can access AppTools.User from initUserDefaultOptionalParameterPackage if you meet the conditions specified in the doc comment for AppTools.User.
An example of when you might use initUserDefaultOptionalParameterPackage is a page that should default to showing information for the currently logged-in user but has a select list or something that lets you look at information for a different user.

Categories

Resources