Sunday, August 24, 2014

Utterlyidle - RESTful Framework for Java Part 1/2

Overview:
This article looks at Utterlyidle, Google Code framework for writing RESTful services in Java. Utterlyidle is written based on totallylazy framework for functional programming. This is a good candidate for writing micro-services in Java.

Here, we will look at a simple example how you could leverage the Utterlyidle as a RESTful framework. The sample will demonstrate two aspects. Firstly, the server API and secondly, the client API usage to access the REST resources. This article will focus on the service API.

You can learn more about this framework here.

A comprehensive sample code for this article can be found here.

Project Structure:


 utterlyidle-sample-rest-app  
 ├── pom.xml  
 └── src  
   ├── main  
   │   ├── java  
   │   │   └── org  
   │   │     └── fazlan  
   │   │       ├── DemoApplication.java  
   │   │       ├── audit  
   │   │       │   ├── AuditHandler.java  
   │   │       │   └── AuditModule.java  
   │   │       ├── common  
   │   │       │   ├── CommonModule.java  
   │   │       │   ├── Json.java  
   │   │       │   ├── JsonResponseRenderer.java  
   │   │       │   └── Repository.java  
   │   │       ├── feed  
   │   │       │   ├── Feed.java  
   │   │       │   ├── FeedActivator.java  
   │   │       │   ├── FeedModule.java  
   │   │       │   ├── FeedRepository.java  
   │   │       │   ├── FeedResource.java  
   │   │       │   ├── Feeds.java  
   │   │       │   └── InMemoryFeedRepository.java  
   │   │       ├── framework  
   │   │       │   ├── CreateResponseFactory.java  
   │   │       │   ├── OkResponseFactory.java  
   │   │       │   └── ResponseFactory.java  
   │   │       └── greet  
   │   │         ├── GreetModule.java  
   │   │         └── GreetResource.java  
   │   └── resources  
   └── test  
     └── java  
       └── org  
         └── fazlan  
           ├── feed  
           │   ├── FeedActivatorTest.java  
           │   ├── FeedRepositoryTest.java  
           │   ├── FeedResourceAcceptanceTests.java  
           │   ├── InMemoryFeedRepositoryTest.java  
           │   └── ObjectMother.java  
           ├── greet  
           │   └── GreetResourceAcceptanceTests.java  
           └── testframework  
             ├── AcceptanceTests.java  
             ├── BDD.java  
             ├── RestClient.java  
             └── utterlyidle  
               ├── Function.java  
               └── UtterlyIdleRestClient.java  

Step 1: Creating the Project


 mvn archetype:generate -DartifactId=utterlyidle-sample-rest-app -DgroupId=org.fazlan -Dversion=1.0-SNAPSHOT -DinteractiveMode=false  

Step 2: Updating the Maven Dependencies


 <?xml version="1.0" encoding="UTF-8"?>  
 <project xmlns="http://maven.apache.org/POM/4.0.0"  
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
      xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">  
   <modelVersion>4.0.0</modelVersion>  
   <groupId>org.fazlan</groupId>  
   <artifactId>utterlyidle-sample-rest-app</artifactId>  
   <version>1.0-SNAPSHOT</version>  
   <repositories>  
     <repository>  
       <id>Utterlyidle - Bodar Repository</id>  
       <url>http://repo.bodar.com/</url>  
     </repository>  
   </repositories>  
   <properties>  
     <mvn.dep.googlecode.utterlyidle.version>742</mvn.dep.googlecode.utterlyidle.version>  
     <mvn.dep.googlecode.gson.version>2.2.4</mvn.dep.googlecode.gson.version>  
     <mvn.dep.testng.version>6.8.8</mvn.dep.testng.version>  
     <mvn.dep.hamcrest-core.version>1.3.RC2</mvn.dep.hamcrest-core.version>  
     <mvn.dep.mockito-all.version>1.9.5</mvn.dep.mockito-all.version>  
     <mvn.plug.failsafe.version>2.17</mvn.plug.failsafe.version>  
   </properties>  
   <dependencies>  
     <dependency>  
       <groupId>com.googlecode.utterlyidle</groupId>  
       <artifactId>utterlyidle</artifactId>  
       <version>${mvn.dep.googlecode.utterlyidle.version}</version>  
     </dependency>  
     <dependency>  
       <groupId>com.google.code.gson</groupId>  
       <artifactId>gson</artifactId>  
       <version>${mvn.dep.googlecode.gson.version}</version>  
     </dependency>  
     <dependency>  
       <groupId>org.testng</groupId>  
       <artifactId>testng</artifactId>  
       <version>${mvn.dep.testng.version}</version>  
       <scope>test</scope>  
     </dependency>  
     <dependency>  
       <groupId>org.hamcrest</groupId>  
       <artifactId>hamcrest-core</artifactId>  
       <version>${mvn.dep.hamcrest-core.version}</version>  
       <scope>test</scope>  
     </dependency>  
     <dependency>  
       <groupId>org.mockito</groupId>  
       <artifactId>mockito-all</artifactId>  
       <version>${mvn.dep.mockito-all.version}</version>  
       <scope>test</scope>  
     </dependency>  
   </dependencies>  
   <build>  
     <plugins>  
       <plugin>  
         <groupId>org.apache.maven.plugins</groupId>  
         <artifactId>maven-failsafe-plugin</artifactId>  
         <version>${mvn.plug.failsafe.version}</version>  
         <executions>  
           <execution>  
             <id>acceptance-test</id>  
             <phase>post-integration-test</phase>  
             <goals>  
               <goal>integration-test</goal>  
               <goal>verify</goal>  
             </goals>  
             <configuration>  
               <includes>  
                 <include>**/*AcceptanceTests.java</include>  
               </includes>  
             </configuration>  
           </execution>  
         </executions>  
       </plugin>  
     </plugins>  
   </build>  
 </project>  

Step 3: Creating the RESTful Endpoint
This is our first service containing a simple endpoint to elaborate the usage of the server API.

 package org.fazlan.greet;  
 
 import com.googlecode.utterlyidle.Response;  
 import com.googlecode.utterlyidle.annotations.GET;  
 import com.googlecode.utterlyidle.annotations.Path;  
 import com.googlecode.utterlyidle.annotations.PathParam;  
 import com.googlecode.utterlyidle.annotations.Produces; 
 
 import static com.googlecode.utterlyidle.MediaType.APPLICATION_JSON;  
 import static java.lang.String.format;  
 import static org.fazlan.framework.OkResponseFactory.ok;
  
 @Path("/greet")  
 @Produces(APPLICATION_JSON)  
 public class GreetResource {  

   @GET  
   @Path("hello/{name}")  
   public Response hello(@PathParam("name") final String name) {  
     return ok(format("Hello %s", name));  
   }  
 }  

Step 4: Creating an Application Module
The above rest service accepts a parameter called name, and returns a greeting message with that name. This service is then wired to the application via a module. Modules are the building blocks of a Utterlyidle application (Modular architecture - vertical silos compared to typical horizontal slices).

 package org.fazlan.greet;  

 import com.googlecode.utterlyidle.Resources;  
 import com.googlecode.utterlyidle.modules.ResourcesModule;  
 import static com.googlecode.utterlyidle.annotations.AnnotatedBindings.annotatedClass;  

 public class GreetModule implements ResourcesModule {  

   @Override  
   public Resources addResources(Resources resources) throws Exception {  
     return resources.add(annotatedClass(GreetResource.class));  
   }  
 }  

We create a module called GreetModule, and wire all the components related to that module.

Step 5: Adding a Module to the Application
Once the modules are created and ready, we can add them as building blocks of our application. One or more modules creates the entire application.

 package org.fazlan; 
 
 import com.googlecode.utterlyidle.Application;  
 import com.googlecode.utterlyidle.RestApplication;  
 import org.fazlan.audit.AuditModule;  
 import org.fazlan.greet.GreetModule;  

 import static com.googlecode.utterlyidle.ApplicationBuilder.application;  
 import static com.googlecode.utterlyidle.BasePath.basePath;  

 public class DemoApplication extends RestApplication {  
   public DemoApplication(String basePath) {  
     super(basePath(basePath));  
     addModules(this);  
   }  

   private void addModules(Application application) {  
     addInfrastructureModule(application);  
     addApplicationModules(application);  
   }  

   private void addInfrastructureModule(Application application) {  
     application.add(new AuditModule());  
   }  

   private void addApplicationModules(Application application) {  
     application.add(new GreetModule());  
   }  

   . . .  
 }  

Step 6: Running the Application
Once all the modules are added to the application, running the application is pretty simple. For this tutorial, we will run the application as a standalone server. This can be achieved as follows,

 package org.fazlan;  

 import static com.googlecode.utterlyidle.ApplicationBuilder.application;  
 import static com.googlecode.utterlyidle.BasePath.basePath;  

 public class DemoApplication extends RestApplication {  
   public DemoApplication(String basePath) {  
     super(basePath(basePath));  
     addModules(this);  
   }  

   . . .  

   public static void main(String[] args) throws Exception {  
     application(new DemoApplication("/")).start(7000);  
   }  
 }  

This would start the server at http://localhost:7000/. Greeting REST endpoint can be accessed at http://localhost:7000/greet/hello/

The endpoint can be accessed either,
http://localhost:7000/greet/hello/FooName or http://localhost:7000/greet/hello?name=FooName

Summary
This article briefly touch based on the capabilities provided by Utterlyidle based on totallylazy in building REST services.

You can learn more about this framework here.

A comprehensive sample code for this article can be found here.

No comments:

Post a Comment