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!
Related
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"}
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.
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
I'm building a DAL for a widget-based reporting application, its been designed in such a way that users pick, configure and deploy reporting 'widgets' to their home screens. Widgets can report across various kinds of company data - sites, brands, employees and so on.
Whilst all users can access all the widgets/reports, all users are not authorised to access all data. If I work for Company-A I can't view sales reports for Company-B or staff attendance data for a salesman at Company-C, however I can configure such a report and add it to my 'dashboard'.
At runtime, an intermediate 'DataService' class has the job of checking the user's credentials and, if access is permitted, returning the appropriate object collection to the client.
On the initial build I just returned an empty List if access to the data was not allowed, but this is also what I do if no data is returned by the report (which can happen). I'd like to show an 'Access Denied' message on the front end if the user isn't authorised to view the data but obviously if all I get back in either eventuality is an empty collection its impossible to know if this was because of insufficients rights or just no data.
I'd be grateful if you could suggest a way of coding around this, my first thought was to move the credential-checking into another object which in turn calls the data access class but time constraints mean this isn't an option.
The only thing I can think of, which goes against everything I've ever learnt, is to throw a custom exception e.g. InsufficientApplicationPrivilegeException if access isn't granted, but this smells bad.
Thanks for reading.
I think you have a couple of options. One is to make a composite object that your data service class returns. The composite object looks something like this: -
class DataResult<T>
{
IEnumerable<T> Data;
Result ServiceResult;
}
ServiceResult contains metadata about the outcome of your service call - it could be an enum which contains e.g. Success, AuthenticationFailure etc. etc.. You can then switch on this in order to do different behaviour.
An alternative option might be to use the NullObject pattern that shows a single item of data in the view which instead of real data simply shows "Access Denied" for the display properties of the object. The advantage of this approach is that your front-end doesn't need to have any conditional logic etc.; however if you want to show a specific message box or similar rather than just displaying a dummy row of data in your widget, then this probably isn't appropriate.
I'm developing an application that does some CRUD operations through a WCF service. The read method returns a complete entity, the update is performed through a legacy system, and only the changed values should be updated.
What is the best way to design the data contract for this scenario without simply sending a dictionary of key-value pairs?
The only other thing I can think of is to make your component durable - i.e. persist its state to a file or database. That way, on the update you can compare the previous state to the state being passed in. I'm not sure that's a good way to go since it will introduce more overhead than just passing in the key-value pairs.
From the outside it might look more CRUDy or whatever, but from a practical standpoint you may be better off just passing some indication as to which values changed.
In case it helps, not sure exactly what you're looking for though ...
In the update request, only act upon fields that are not null.
In addition wrap any non-nullable types in a nullable structure.
As an example ...
Update( Nullable<int> orderNumber,
Nullable<DateTime> orderDate,
Nullable<bool> isComplete )
{
if( orderNumber != null )
databaseRecord.OrderNumber = orderNumber;
if( orderDate != null )
databaseRecord.OrderDate = orderDate;
if( isComplete != null )
databaseRecord.IsComplete = isComplete;
}
the best way to do this is with property dictionary, just represent your entities as dictionary of property name and value.
save all changes in some list and pass a partial dictionary with all changed properties.
i think this is best design,
if u wanna avoid this design, send entire entity with some list of changed properties.
(to save transport u can put null on other properties)
if u don't wanna change the service contract signature u can push the names of modified properties on the header
I had two ideas of how to achieve this;
Have the client send both the original entity, and the changed entity in full, the service would then figure out what properties were changed.
Use a pattern similar to Nullable, lets call it Modified with an IsModified flag and a NewValue property of type T. Each property of the DataContract would be of this type, the service can check the IsModified flag when performing the update.
The legacy sytem we use has an api that accepts String.Empty to identify unmodified fields, a '?' character is used to indicate an update to an empty string. I really don't like this, the user of the api is forced to read the documentation, and if you actually want to store a '?' you can't. I want our webservice api to be more explicit.
You can use DataSet to keep your changes. Call your record as DataSet then assign some values to the record. DataSet.Tables[0].GetChanges() will give you the columns which were changed.
You could leave the data contract alone and update your service contract. Just represent the required fields for the method as properties within the service contract. Any consuming application using the service will have to be updated if the service contact changes, but the consuming application will know what is required to successfully update the data.
There are positives and negatives to this method, but I use it when a method I am writing doesn't require the full data contract.
--Edited for a spelling error--
Looking at your requirements and statements, i've made a few assumptions before starting to write my vision on a possible solution:
You are using the same class for retrieving (return value type of "read" operation) and updating an item (input parameter type of "update" operation) in your WCF service.
Your current problem of implementation is how to use the original class (not a dictionary) AND still be able to determine 'what has changed compared to the read' when you get the "Update" operation called on your WCF service
You are writing both the server and client. Both are written using the MS .Net framework.
If this is true, the problem lies in the Update method missing information. The information required is 'has changed' which could be inferred if a 2nd state is present to compare against or should already be present along side the state to update in the back-end.
Since you only have the 'back-end state' (without flags) when the client posts its data to the WCF service, how should we determine what did change? Obviously, we want to prevent another 'read' roundtrip to get the current server state and start comparing.
Sending the original & changed state from the client to the server is a possible but heavy solution. Next to that, the client isn't interrested in this information, the server is.
Adding this all up makes my guess is that changing the type of the 'Update' operation input parameter is the easiest way to go. Create a decorator class that adds 'dirty bit' behavior to the original entity. Use this new class as input parameter for your "Update" operation. You then will have the availability in the server to check this dirty bit next to the full state send by the client. The major change on the client side is that the object needed for the 'Update' operation is no longer the same as the one provided by the 'Read' method. To eleviate this pain, i would probably create a decorator class which added the required 'dirty bit' handling. This only requires the object instanciation to change, while maintaining the interface signature for the client (very little code changes).