Friday, September 19, 2014

Create an Ajax Web Client for OData Web API RESTful Service - HTTP-PATCH JSON


In this post we'll create a web client for updating a record by sending an HTTP PATCH request via Ajax to an Web API OData RESTful service implemented with the ODataController. We'll construct the update form using the Twitter Bootstrap.
Tu update an item, we'll perform an Ajax PATCH request using the OData protocol.

In this article we're using an OData Web API which we built in a previous Web API ODataController tutorial. The instructions for the Bootstrap's setup can be found  in this short article.
The OData protocol designed for the MVC Web API with ODataControllers can be read at the Microsoft Asp.Net official site

For this exercise we use an Entity called "Note" , and we'll want to send an HTTP  PATCH request to the OData HTTP Web API service to update the record. The final product to perform the Ajax PATCH will be shown this way:



First create the MVC application as an empty web site:




Then import the CSS3 and javascript files  (you can learn the 5 minutes Twitter Bootstrap installing instructions here) : also, after you do so, check that you have brought all required files:


Open and look at the Web API ODataController class, to see the PATCH( Delta<Note> ) method we're going to use:



You can see that the Patch() action method requires a "Delta<Note>" object , and returns an  IHttpActionResult object: a code 200 (OK) response if everything went right, and an 400 error response code if don't.
Important:
Keep in mind that we will send a PART of an Item inside the request's body: we send ONLY what was changed, and not a legal record. That's why at the OData Web API the gotten object is a "Delta<Note>" object and not a "Note" object. That means, the object we send through the Ajax request is usually an illegal Note, an object which does not comply with the DataAnnotations set at the Model layer.

Create a new html file:


Add the references to the CSS3 Twitter Bootstrap files:



Then we add an input type=number for selecting the KEY of the item to fetch:

Next, we append all the DOM elements for displaying all of the item's details, inside  a panel set according to  the Bootstrap classes design:


This is the markup to copy-paste:

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title>Update</title>
    <link href="Content/bootstrap.css" rel="stylesheet" />
    <link href="Content/bootstrap-theme.css" rel="stylesheet" />
</head>
<body>



    <div class="container">
        <div class="jumbotron"  align="middle">
            <h1>OData Web API Update Form</h1>
            <p>Ajax HTTP GET/PATCH Form to show Details & Update an item</p>
            <p style="font: 900 11px Georgia;">By Carmel Shvartzman - using the Twitter Bootstrap</p>
            
            <p><a class="btn btn-default btn-lg" role="button">Learn more about OData Web API</a></p>
        </div>


        <div class="panel panel-default">
            <div class="panel-heading row">
                <div class="text-muted col-xs-6">
                    <h2>Message Details</h2>
                </div>
                <div class="text-muted col-xs-3">
                    <div class="editor-label">
                        ID
                    </div>
                    <div class="editor-field">
                        <input type="number" name="ID" value="3" class="form-control" />
                    </div>
                </div>

            </div>
            <div class="panel-body text-muted">
                <div class="row">
                    <div class="col-xs-6">
                        <div class="editor-label">
                            To
                        </div>
                        <div class="editor-field">
                            <input type="text" name="To" class="form-control" />
                        </div>
                    </div>
                    <div class="col-xs-6">
                        <div class="editor-label">
                            From
                        </div>
                        <div class="editor-field">
                            <input type="text" name="From" class="form-control" />

                        </div>
                    </div>
                    <div class="col-xs-12">
                        <div class="editor-label">
                            Heading
                        </div>
                        <div class="editor-field">
                            <input type="text" name="Heading" class="form-control" />

                        </div>
                    </div>
                    <div class="col-xs-12">
                        <div class="editor-label">
                            Body

                        </div>
                        <div class="editor-field">
                            <input type="text" name="Body" class="form-control" />

                        </div>
                    </div>
                    <div class="center">
                        <div class="center">
                            <br />
                            <div class="row">
                                <div class="col-lg-6">
                                    <input class="btn btn-sm btn-default" value="See Message Details" />
                                </div>
                                <div class="col-lg-6">
                                    <input class="btn btn-sm btn-default" value="Update Message" />
                                </div>
                            </div>
                        </div>
                        <br />
                        <div class="alert alert-success message"></div>
                        <div class="alert alert-danger error"></div>
                    </div>
                </div>
            </div>
        </div>
    </div>  




After the markup, write the javascript, with the references to the files:

When the "Details" button is clicked, we send an Ajax request with the ID of the record to be displayed :



If the response was an OK, we proceed to fill all fields; else, we show an error message:


This is the code for the script:


 <script src="Scripts/jquery-2.1.1.js"></script>
    <script src="Scripts/bootstrap.js"></script>
    <script>
        $(function () {
            $("div.message").css("display", "none");
            $("div.error").css("display", "none");

            $("input.btn[value*=Details]").click(function () {

                var id = $("input[name=ID]").val();
                $.ajax({
                    url: "http://localhost:6954/OData/Notes(" + id + ")",
                    type: "GET",
                    data: id,
                    dataType: "json",
                    contentType: "application/json",
                    beforeSend: function (data) {
                        //alert(id);
                    },
                    success: function (data) {
                        var note = data;
                        $("div.error").css("display", "none");
                        $("div.message").css("display", "block");
                        $("div.message").text("The Message with ID = " + id + " was retrieved successfully!!!");
                        $("input[name=To]").val(note.To);
                        $("input[name=From]").val(note.From);
                        $("input[name=Heading]").val(note.Heading);
                        $("input[name=Body]").val(note.Body);
                    },
                    error: function (msg) {
                        var oError = JSON.parse(msg.responseText);
                        fnError("Error : " + oError.error.innererror.message, id);
                    }
                })
            });

            function fnError(msg, id) {
                $("div.message").css("display", "none");
                $("div.error").html("The message with ID = " + id + " does not exist. Try again.");
                $("div.error").css("display", "block");
            }


The action method inside the ODataController returns the required item:



Now, we need another $.ajax method to UPDATE the EDITED record:



This is the code for copy-paste in your project:


            $("input.btn[value*=Update]").on("click", function () {
                var id = $("input.form-control[name*=ID]").val();
                var to = $("input[name=To]").val();
                var from = $("input[name=From]").val();
                var heading = $("input[name=Heading]").val();
                var body = $("input[name=Body]").val();
                var data = '{"ID":"'+ id +'","To":"' + to + '","From":"' +
                    from + '","Heading":"' +
                    heading + '","Body":"' + body + '"}';

                $.ajax({
                    url: "http://localhost:6954/OData/Notes(" + id + ")",
                    type:  "PATCH", 
                    data: data,
                    contentType: "application/json",
                    dataType: "json",
                    success: function (data) {
                        $("div.message").text('The item was successfuly updated.');
                    },
                    error: function (msg) {
                        $("div.error").html(msg.responseText);
                    }
                });
            });
        })
    </script>

All we do here, is to create an JSON object with the data entered by the User, and to send an Ajax HTTP PATCH request to the OData Web API web service.

Build & run the application.  After the User gets the item's details, EDIT some of the data, and clicks the second button, for updating the record:







The Ajax request comes to the web service, which we built in a previous tutorial about setting an OData v4.0 WebAPI with updating support (HTTP PUT & HTTP PATCH) and can be found here.
This is the method which handles the request at the web service:



See what is inside the Delta<Note> object :



The record was updated.
In case of an error,  for example, if we don't respect the data annotation for the "From" field, which requires an email as input, we get the error message:  



That's all!!!!

In this post we've learned step by step how to build a web client which retrieves and updates a record from a database by sending an HTTP PATCH request via Ajax to an WebAPI OData RESTful service implemented with an MVC ODataController.
Enjoy coding.....

By Carmel Shvartzman

עריכה: כרמל שוורצמן