Monthly Archives: April 2017

Play Framework and CORS with Angular2 Client(Cross Origin Resource Sharing)

Play Framework and CORS with Angular2 Client(Cross Origin Resource Sharing)

Although Play framework allows us to write complete web application including UI. But we can just keep our REST based HTTP service in Play Framework and access them from any other application hosted on another server. But as soon as you do it, you start getting complaints about CORS issues. For our safety, we are not allowed to request the service from a web request started on another web server. In this post, we are going to see how we can enable CORS support in our Play framework based service.

You might first download Activator. It makes it easier to start with scala application by doing the necessary scaffolding to get you started. Please download it from the following if you don’t already have it. I am sure you wouldn’t regret.

Activator Download

Activator Download

It is downloaded as a zip package. We can extract it into a folder:

Open Activator

Open Activator

Running it for the first time can bring any required dependencies to run it.

Activator running

Activator running

Let’s first create a Play framework service using Activator. Let’s name it as Echo Service. You guessed it right, it would just echo the data sent to it. It accepts data with a Message field (string). It responds with the contents of the field as part of its web response.

Activator new

Activator new

Debugging the Service

Let’s now add the debug configuration for play framework based service. Here we are selecting Play from debug configuration to be used for our service.

Add Play Debug Config

Add Play Debug Config

We are running it on port 9000. It is the default port.

Screen Shot 2017-04-22 at 11.46.19 AM

Add EchoController
Let’s first add EchoController. It just has an action. The action accepts single parameter of type string. It just returns the message back in the form of Ok response.

Now we can update routes so that play framework can route the requests to our controller. We have commented all routes and just added a route for echo action for EchoController.

Let’s now hit the service using PostMan. Here we are passing the message as part of the query parameter, as expected by the EchoController. As expected, we are getting the same message echoed by the service.

Angular2 Client

Now let’s create a client to use our Echo Service. Since this would be hosted on a separate host, we can create a scenario of Cross Origin request for the service and discuss how we can resolve the issue. Here we are creating an Angular2 client. We are naming the Client as EchoServiceClient, which is certainly very intuitive :)

Echo Service Client

Echo Service Client

Let’s start by adding EchoRequestService in services folder in app.component. The service just has a method which accepts a message as an argument. It sends an Http request to our Echo Service running on port 9000. Angular2’s Http module returns an Observable<Response>. Here we are just extracting the response’s text from and returning Observable<String> from the method. The class is decorated as Injectable so that we could inject it to app.component.

Let’s turn our attention to app.component.ts. Since we just need EchoRequestService in this component, we are adding it to the providers section in the component’s decorator. We are also injecting the service in the component’s constructor. The component has two properties inputMessage: String and echoedMessage: Observable;. It also has sendEchoRequest() method which just uses EchoRequestService and assigns the result to the echoedMessage.

Now we just need to update the template to use the properties from the component. We are binding the inputMessage property to a text box. This is a two way binding. We are also using echoedMessage property. We are using async filter since this is an Observable.

Since we already have the play framework service running, we can just ng serve the angular2 project. This runs as localhost:4200 by default. We enter some message to the text box and click the button. To our surprise, we get the following error based response from play service.

Cross Origin Request Not Allowed

Cross Origin Request Not Allowed

CORS Resolution

This is actually a common problem when we request another service from another web application hosted separately. Here we need to build some kind of relationship between the two applications. This requires play framework service to recognize our Angular application running as localhost:4200 as one of the allowed origins. But this requires a bit of plumbing.

First we need to add filters as dependencies to build.sbt. This changes the build.sbt as follows:

This would add necessarily dependencies to our service by adding the necessary library references. This includes availability of CORSFilter. We need to just update Filters to use this filter. Now the request pipeline would use CORSFilter as one of the filter before serving the resource as specified by the route.

But this is not enough. We still need to add localhost:4200 as one of the allowed origins. Actually CorsFilter configuration is already added to application.conf. It’s just commented out. We can just uncomment the following section and add localhost:4200. In case we need to allow all origins, we can just assign null to it.

Now we can run the service again. We notice that the play framework service now honors the request from Angular application running on localhost:4200 and echoes the response as expected.

Echo Success

Echo Success

Code

Create In-Memory file & Downloading Data in HTML5 / Javascript

Create In-Memory file & Downloading Data

In this post we are going to add ability to create an in-memory file and add ability to download it using a link and a button.

In-Memory

Here is an HTML file. Here we are adding a Link with download attribute set as Download2.csv. This would download the file as Download2.csv as user clicks the link. We have also added a button. Clicking the button would call ExportData() function, defined later.

<html>

  <head>
    <link rel="stylesheet" href="style.css">
    <script src="script.js"></script>
  </head>

  <body>
    <h1>Create In-Memory file & Downloading Data</h1>
    
    <a id="aDownloadCsv" download="Download2.csv">Download Link</a>
    
    <p/>
    
    <button onclick="ExportData()">Download Button</button>
    <script>
      AssignDataToLink();
    </script>
  </body>

</html>

We have also call AssignDataToLink(), which should assign the code to the anchor tag to download the file. We have also added a script file reference script.js in the scripts section of the above HTML file.

We have defined AssignDataToLink() in script.js. It creates the data as comma separated values. We are also adding the data to href of the anchor tag.

function AssignDataToLink() {
  	var csv = "Id,Value\n1,Muhammad\n";
		var data = new Blob([csv]);
		var downloadLink = document.getElementById("aDownloadCsv");
		
		downloadLink.href = URL.createObjectURL(data);
}

Additionally, we are defining ExportData() function in script.js. It also creates some comma separated data, creates a link and add it to the DOM. We just call the click() for the anchor tag.

function ExportData() {
  	var csv = "Id, Value\n1,Muhammad\n";
		var data = new Blob([csv]);
		var downloadLink = document.getElementById("aDownloadCsv2");
		
		if (downloadLink == null) {
		  downloadLink = document.createElement('a');
		  downloadLink.setAttribute('download', 'DownloadedFile.csv');
		  downloadLink.setAttribute('id', 'aDownloadCsv2');
		  
      document.body.appendChild(downloadLink);
		}
		
		downloadLink.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(data));
		downloadLink.href = URL.createObjectURL(data);
		
		downloadLink.style.display = 'none';
		downloadLink.click();
}

Code

Plunkr