About Me

My photo
Senior Java Engineer, Wavecell Pte Ltd. Singapore

Wednesday, November 8, 2017

Handling POST request using akka-http in a akka-actor system

Akka-htp is a well known module for providing full server side as well as client side http stack currently supporting Scala and Java language bindings. Among other Java Rest frameworks/libraries such as Spring-boot, Play Framework, JAX-RS, Jersy or Scalatra, akka-http is more preferable in applications where high throughput and concurrency is expected.

Akka-http is not a full MVC framework like Play or not require a container to run like scalatra. As it is based on akka-actor and akka-stream modules inherently reactive and works well with message driven systems. As it supports for different levels(low level and high levl) of APIs makes it easy to adopt and ease of deployment.

Here is a simple example of using Akka-http high level API in Java in a akka-actor system.

First we need following dependencies to be included in our project.




Here we initialize the http server and bind with the akka system. 

We can define our router class by extending 'AllDirectives' class as follows. We use this to get a Route object while initializing the 'routeFlow' as above.

import akka.http.javadsl.model.ContentTypes;
import akka.http.javadsl.model.HttpResponse;
import akka.http.javadsl.server.AllDirectives;
import akka.http.javadsl.server.Route;

import static akka.http.javadsl.server.PathMatchers.integerSegment;
import static akka.http.javadsl.server.PathMatchers.segment;

public class Router extends AllDirectives {

    //host:port/api/{userId}/{resourceId}
    public Route createRoute() {
        return route(
                pathPrefix(segment("api"),
                        () -> pathPrefix(integerSegment(),
                                userId -> pathPrefix(segment(),
                                        resourceId -> pathEndOrSingleSlash(
                                            () -> processRequest(userId, resourceId))
                                )
                        )
               )
        );
    }

}

In the processRequest method we provide the POST request handler which returns a 'akka.http.javadsl.server.Route' instance.
    private Route processRequest(args...) {
        return post(() -> entity(handler...)
        );
    }

Based on the request body (Content-Type) we can use a specific Unmarshaller to access request body data. As an example in order to parse the JSON request body we can use a Unmarshaller provided by 'akka.http.javadsl.unmarshalling.Unmarshaller' , 'akka-http-jackson-experimental_2.11' package, Gson etc.

Using akka.http.javadsl.marshallers.jackson.Jackson;
      {
         "name": "Sam"
         "count" : 10
      }
     public class Request {
       String name;
       int count;
     }
import akka.http.javadsl.marshallers.jackson.Jackson;

public Route processRequestUsingJackson(int userId,String resourceId) {

        return post(() -> entity(Jackson.unmarshaller(Request.class),
                                    content ->
                                        completeWithFuture(
                                            CompletableFuture.completedFuture(
                                                HttpResponse.create()
                                                .withEntity(ContentTypes.APPLICATION_JSON, "{\"msg\":\"Success\"}")
                                            )
                                        )
                                )
        );
    }

Here we use default akka Unmarshaller package to parse entity to string and then Gson to get the Java object.

import akka.http.javadsl.unmarshalling.Unmarshaller;
import com.google.gson.Gson;

private Route processRequestUsingGson(int userId,String resourceId) {

        return post(() -> entity(Unmarshaller.entityToString(), content -> {

                    final Gson gson = new Gson();
                    final Request requestBody = gson.fromJson(content, Request.class);

                    return completeWithFuture(
                                CompletableFuture.completedFuture(
                                        HttpResponse.create()
                                        .withEntity(ContentTypes.APPLICATION_JSON, "{\"msg\":\"Success\"}")
                                )
                    );
                }
            )
        );
    }

Monday, October 30, 2017

Uploading maven artifacts to a ftp location using SFTP protocol.

Apache Maven Wagon is a set of plugins developed to provides a transport abstraction for handling maven artifacts and repositories. Shown below is the way to use 'wagon-ssh' plugin to upload maven artifacts to a ftp location using the SFTP protocol.

This is quite straight forward and requires few elements to be configured in the pom.xml as follows.

1. Configure repository location of the wagon-git plugin.


        
            synergian-repo
            https://raw.github.com/synergian/wagon-git/releases
        

2. Include the 'wagon-ssh' plugin extension configuration inside the 'build' element.


        
            
                org.apache.maven.wagon
                wagon-ssh
                2.8
            
        

3. Finally we need to include our ftp location using the 'distributionmanagement' element. During the build process artifacts will be uploaded in to following location.


        
            mvn-ftp-server
            sftp://ftp.aravinda-sites.com/my-ftp-repo
        

In order to use SFTP protocol maven settings.xml need to be updated with the ftp server access keys. Here the 'id' defined in the repository should match with the server id.


    
      mvn-ftp-server
      /Users/aravinda/.ssh/id_rsa
      passPhrase
  

Now you can execute,
'
mvn deploy

command to upload the artifacts.

Thursday, August 17, 2017

Changing max pass through request body size in Nginx for AWS Elastic Beanstalk

Most of the NodeJS applications in Elastic Beanstalk uses a Nginx as reverse proxy which routes requests from port 80 to 8080. Reason being the out of the box NginX support for NodeJS applications in beanstalk.

Recently i was working in a nodejs application which uploads images and video files to AWS S3 and our deployment environment is Elastic Beanstalk.

With the default Nginx configuration i came across following error when i try to upload large files.

-------------------------------------
/var/log/nginx/error.log
-------------------------------------
2017/08/17 08:12:16 [error] 20884#0: 
*526 client intended to send too large body: 41324010 bytes,
client: 10.0.0.10, 
server: , request: "POST /filelink/upload HTTP/1.1", 
host: "fileuploader***.elasticbeanstalk.com"
-------------------------------------

As clearly mentioned in the log Nginx doesn't allow requests with large body to pass through it. Default max value is ~2MB. 

Elastic beanstalk allows this kind of configurations to be manipulated via, .ebextensions. What we need to do is to create a folder as .ebextensions in your root directory of the node project and add a SOME_NAME.config file to it with the following Nginx configuration. Here we are changing the property, client_max_body_size to 50M which increases the pass through file size.

files:
  /etc/nginx/conf.d/proxy.conf:
    content:  |
      client_max_body_size 50M;

Here is a sample nginx configuration from official documentation.


Let me know your thoughts.

Handling POST request using akka-http in a akka-actor system

Akka-htp is a well known module for providing full server side as well as client side http stack currently supporting Scala and Java langua...