HTTP Posting of data in AngularJS
Posting HTTP data within the Angular framework requires the use of the $http angular service. The reUrgency 2.0 programming practices have us interacting with server-side data through the use of RESTful services. This allows us at reUrgency to utilize the $resource service within the Angular framework. The $resource service is a wrapper around $http service which makes it easier and more efficient to consume RESTful services.
The $resource service requires the file angular-resource.js. This service must first be loaded within your application.
Once the $resource service has been loaded it has the following usage pattern.
The Angular module can then be setup with multiple factory patterns that return $resource services. Below is an example of one such factory within the Derby app.
By giving the service a name, in this case DivisionService, the service can be referenced and used anywhere within your Angular application, or even across Angular applications as is being done within the Derby project.
The above example is creating a $resource service. The new service, as previously mentioned, is called DivisionService and it also has a new action called “update” which is mapped to the “PUT” HTTP verb.
This blog entry is about the posting of data. Below is a code snippet of another one of our Derby $resource services. This one is called AssignLaneService.
The Angular $resource service supports the main HTTP verbs/methods of GET, POST, and DELETE. Why the PUT verb was neglected is anybody’s guess. As you can see in the PUT example above, the $resource action of “update” was created and mapped to the HTTP verb “PUT”. Angular gives you the default actions listed below.
So if a developer wanted to post data using the AssignLaneService above, they would call the “save” action on that service.
Below is an example of one more $resource service within the Derby application and it is called RandomizeHeatService. The RandomizeHeatService service and the AssignLaneService will be the focus of this blog entry going forward.
These two services, RandomizeHeatService and AssignLaneService , randomly assign drivers to a heat and assign a driver to a lane withing a heat. They both take some input, make an insert into the database (along with some other functionality), and return the appropriate object. When I originally created these two services, I was using HTTP GETs to perform this transferring of data. HTTP GET, however, should only be utilized when requesting data, not when modifying data. Using HTTP GET to modify data does not follow the REST standard. To modify data within the REST environment, POST or PUT should be used. It is debatable whether in my usage I should be using a PUT or a POST. I settled on using POSTs for the two services above.
When POSTing data within Angular using the $resource service, the $resource service will post your data as an object. I ran into this problem with the RandomizeHeatService. The server-side WebApi controller only requires the ID (which is an integer) of the selected heat to do its magic. However, I could not just pass that integer ID because Angular would take that integer and wrap it inside an object. So on the server-side I had to create a custom class with only one property. This custom class is shown below.
By the way, this custom class was created within the Model layer as an entity (but this “entity” is not allowed to be added to the database as a table). It seems like overkill to create a class just so we can pass a single integer, but it appears that is what is required by Angular.
The AssignLaneService has several parameters that need to be passed to the server. It made much more sense to create a class in this instance. The custom class used to pass data to the server within the AssignLaneService is shown below.
You might ask why I didn’t use an existing entity as my input parameter and that would be a valid question. However, the nature of our database structure and the data actually inputted by the end user (namely the driver number) do not exist within a single entity. For this reason, the class above was created within the Model layer to handle the inputted data. The server-side code handles all of the relationships between the various entities.
With the two input classes created for our WebApi controllers, the actual function signatures for the server-side C# code are shown below.
Note the “HttpPost” decoration on both methods. That will tell the WebApi controller that both of these methods are POST methods. Normally, you can just use the default methods of “Put” and “Post” within a WebApi controller, but we created custom post methods for each WebApi controller because neither method strictly posted the entire entity defined by its WebApi controller.
This causes the URL for the REST service to include the respective method name as shown at the beginning of this blog post for the RandomizeHeatService and AssignLaneService services.
Originally, I was not passing back to the client an HttpResponseMessage. Doing that did not follow the practices of REST. When data is posted to the server, the client expects back an HttpResponseMessage. Below is the server-side C# code that creates the HttpResponseMessage return object. Please note, that according to the REST standard, within the return header the location of the newly created resource should be included.
In order to utilize either REST service provided by the server, the client can take advantage of the Angular services RandomizeHeatService and AssignLaneService created from before. An example using the AssignLaneService is shown below.
As you can see from the above JavaScript, an object was created with properties that match our custom server-side entity. These properties are then assigned values and passed to the server via the “save” action of the AssignLaneService (the “save” action by default being a POST).
Lastly, the “save” action expects two function handlers to be provided. One for a successfully returned status code (in the case of a POST, a 201 code) and another to handle error status codes. These functions can either be inline anonymous functions or references to functions. The example above uses inline anonymous functions.
Hopefully, reading this blog post will give you a better understanding of how to POST data using Angular.