CORS Stateless REST Service with detached HTML5 client

Introduction

This blog will detail in precise steps how to create a stateless REST service that is consumed by a HTML5 client on another domain. The HTML5 client could easily be a Cordova or Phonegap app.

The HTML5 client is simple and basic just for demonstration purposes. It shows the characteristics necessary for Cross-Origin-Resource-Sharing (CORS) communication.

The REST service is also simple. It demonstrates how to enable CORS on the server application.

While both Client and Server projects are proliferated throughout this blog, the completed artifacts are available for download at the bottom of this page.

Related Posts

Authenticating a REST Service using Facebook authentication http://outbottle.com/cors-stateless-rest-service-with-facebook-authentication/

Adding JSON Web Token (JWT) enhancements to “Authenticating a REST Service using Facebook authentication” http://outbottle.com/json-web-token-jwt-with-cors-stateless-rest-service-with-facebook-authentication/

Background

Please refer to this previous blog for a quick to the point introduction to CORS and how to enable it in general. That blog is something of an abbreviated version of this one. It demystifies CORS through example and explanation. It is a good prerequisite before following this worked example.

This blog will show the following:

  • How to build a Stateless REST service using the wonderful Ninja Framework. If you haven’t seen the Ninja framework yet, you’re in for a real treat. Netbeans is the chosen IDE for good reason; its Maven support is truly fantastic. The Ninja Framework is delivered through maven.
  • How to build a HTML5 client using Netbeans.
  • The steps required to enable CORS communication between the client (using JQuery) and the Server application.

If you’re not wild about using the Ninja Framework and would prefer Spring or Spark or the likes, this blog can still be of help to you as the steps and concepts are applicable to any MVC architecture.

Why the Ninja Framework?

  • It is an excellent MVC framework.
  • It’s effortless to get up and running.
  • It just works with absolute minimal configuration.
  • Pretty much any components required for a modern web application are all boxed into Ninja by default. E.g. A dependency Injection container, JPA, Email and loads more.
  • It’s stateless. This is one of the real attractions with it. It’s a 100% perfect fit for facilitating HTML5 clients, mobile applications and web applications alike. You can be up and running in no time at all.
  • It’s a full-stack framework but in this example we’re just using its out-of-the-box, effortless, stateless REST capabilities.
  • Excellent documentation.
  • Scalable by default.

If you haven’t tried it, do so now by following this tutorial, you will be surprised at just how perfect the Ninja framework is for such a CORS application.

Setting up the Ninja Framework Application Using Netbeans and Maven

On Netbeans go File -> New Project -> Maven -> Project from Archehtype

Search for ninja archetype and chose the ninja-servlet-archetype-simple

Choose the project name and location

Hit finish.

Now that the project has been created, navigate into the Source Packages and delete the following packages:

  • assets.css
  • views.ApplicationController
  • views.layout
  • views.system

OK, why? Because we’re building a REST service to be consumed by JavaScript, we have no use for views. The views will be within the HTML5 client.

Add a new package called models.

Create a new Java class in ‘models’ called Person.

Update ApplicationController to have just one method, specifically, person(Person person): Result

At this point, the unit tests will break. Feel free to delete them for now, this is not an exercise in Unit Testing.

Update Routes.java to have just the following route.

This code is self-explanatory, each route just points to the controller method that will handle the request.

Status Update

The ninja framework application has been created. We’ll run it in a moment with Maven. The application is not yet CORS enabled. This is intentional in order to demonstrate the many pitfalls when enabling CORS.

 

Creating the HTML5 Client

In Netbeans: File -> New Project -> HTML5-> HTML5 Application

Choose an appropriate name and location.

Do not choose a site template.

Do however add jquery

(Isn’t that convenient?)

Anyway, note that JQuery 2.x.x (as opposed to 1.x.x.) does not support IE6, 7 or 8 http://blog.jquery.com/2013/04/18/jquery-2-0-released/ (Those browsers don’t support CORS anyway)

index.html will open by default.

Drag /js/libs/jquery.js into the head tag of index.html to add it to the page.

Create a new JavaScript file under folder js called js.js.

Drag js.js to the head element of index.html BELOW jquery

All that is just to achieve this:

Now, let’s add the following basic JQuery ajax calling stuff to js.js (entire contents of js.js)

 

Note the headers in the AJAX request. “X-Foo-for-demo-only” is there to emphasize that any headers supplied by the client must be approved by the Server application. The property “Content-Type” will result in the header “Content-Type”, therefore this header needs to be approved by the Server application too.

 

Status Update

We’ve now created a HTML5 client which can talk to our other-domain service. Our service however is not yet equipped to permit CORS requests. The following chapter will examine the CORS communication process. CORS is not yet enabled so the communication will fail. The various problems and solutions are addressed in turn.

 

Enabling CORS

Run the CorsRestService Ninja Framework project by executing the maven jetty run goal

Ordinarily, one would now navigate to http://localhost:8080 to access the application now running on jetty but in our case we have nothing to see, our application only handles a single POST request at the moment, so navigating there yields a 404 not found page.

So now, run the html5 project. (Do install the chrome Netbeans plugin if asked if you don’t currently have it, it’s excellent. We’re not going to use it here though). While the instant feedback from the Netbeans chrome plugin is really excellent to work with, personally I prefer using firebug (for Firefox) for what we’re about to demonstrate.

Navigate to the HTML5 app URL in firefox (http://localhost:8383/CorsRestClient/index.html). Ensure that firebug is open.

You should now see a page with a button.

Open the “Net” tab in firebug. Hit the ‘Test CORS’ button on the HTML5 application. If you’re familiar with CORS, the result will not surprise, if you’re a novice, the request sent may seem unexpected. The OPTIONS HTTP method is the Preflight request. Note the “Cross-Origin Request Blocked” message in the “Console” tab. In addition to this there is a 404 not found message. The 404 is the real problem here.

If you’re reading this blog it’s quite likely the reason you’re here is because of that dammed message. Well, here’s the solution….

(Preflight and CORS in general are examined in succinct detail here.)

Now, here’s what you need to do…..

Setup a Preflight Request Endpoint

Note the 404 not found message accompanying the Cross-Origin message. This is because the OPTIONS request has no corresponding Controller method. There’s obviously a Controller Method (end-point handler) for the POST request but not for the OPTIONS Preflight request.

The ninja framework makes very light work of setting up the necessary end-point, firstly, in conf.Routes.java add a catch-all /* route, specify OPTIONS as the method. Create a matching controller method end-point handler.

 

 

The ninja project updates automatically on save. Now hit the ‘Test CORS’ button again and observe the response this time.

The 404 not found aspect of the problem is gone, we still have our Cross-Origin Request Blocked problem though.

 

Setup the CORS Filter

So, lets add a filter in package ‘filters’ to supply the necessary response headers to permit CORS requests. This is where the ninja framework really shines; this process could not be simpler.

Create the following class in a package called filters:

 

Add the filter to the controller at the class level. The POST response must also supply the headers so applying the filter at a class level will apply it to all methods of the controller.

 

The Ninja Framework will update the application automatically on save. How hit the ‘Test CORS’ button again. This time, the request succeeds. In fact, both requests succeed. I.e. the Preflight request and the actual POST request both succeed.

 

The CORS Filter

Your server application needs to handle the OPTIONS and POST request by sending back a response with the following headers

Access-Control-Allow-Origin * allows access from any domain. The * can be replaced with a comma separated list of specific domain url’s e.e. http://google.com, http://ninjaframework.org

Access control methods is the permitted HTTP method types.

Max age is REALLY IMPORTANT FOR DEBUGGING and important for performance in a complete application. Once the OPTIONS preflight request has gone through once, it is cached for the number of seconds specified in this header. For that specified number of seconds, the actual request can go through with the OPTIONS negotiation. So, if you’ve got a number in here and you’re chopping and changing code, the changes may not be fully reflected due to the fact that the request is cached and the preflight request is not being issued.

Allow headers: Any headers sent by the client must be specified here otherwise the CORS request will not succeed and you’ll see the dreaded cross origin error message in your browser.

The client will be specifying content-type = application/json so the response header Content-type is mandatory. The other header here is custom, for demo purposes only. The server must acknowledge this header too for the request to succeed. (Any header sent by the client needs to be permitted by the server application).

 

The CORS Filter – additional requirement

Because the OPTIONS Preflight request does not deliver a payload, it may be very undesirable to move through the filter chain. Ideally, the CORS filter should be the first and only filter as far as the OPTIONS Preflight request is concerned.

To that end, the following modification to the filter will detect the preflight request, still return the CORS enabling headers but not delegate to the next Filter, the response is issued immediately.

 

Conclusion

This blog shows how a CORS enabled REST service can be created using the Ninja Framework. A somewhat generic HTML5 client has been enabled to communicate with the Service Cross-Domain. This client could easily be a Cordova/Phonegap application.

There are a number of obstacles to overcome when enabling CORS. Those issues have been identified and examined. Solutions to those problems have been provided.

CORS itself is not examined in full detail, it is explained within the context of this example. For full detail on CORS, please see this blog.

Downloads

HTML5 client : HTML5CorsRestClient

(Note that it is best to run this from inside a web-application-server such as the Chrome netbeans plugin or Mongoose)

CORS enabled service Maven project (Ninja Framework): CorsRestService

 

Questions and comments are always welcome.

 

Related Posts

Authenticating a REST Service using Facebook authentication http://outbottle.com/cors-stateless-rest-service-with-facebook-authentication/

Adding JSON Web Token (JWT) enhancements to “Authenticating a REST Service using Facebook authentication” http://outbottle.com/json-web-token-jwt-with-cors-stateless-rest-service-with-facebook-authentication/

1 Comment