26 January 2015

REST Web Services Part 2 - Java

Sometime last year, I started what I hoped would be a blog post series on REST in various languages.




Part one was using CFML and Taffy. Due to the usual complaints of time and patience it’s taking me forever to continue it, but hey ho. Here’s the second part. In this one I wanted to look at a java implementation of REST services. To make it more interesting I wanted to use Google App Engine (GAE) for hosting. Google App Engine is a great resource for testing as its pretty solid and a generous with its free quota. Plus it frees me from the worries of settings up a proper environment.


Obviously using Java for REST and then forcing all of this into the specifications of GAE may prove a little tricky. However I'm sure there are some technologies out there which do all the hard work leaving me to just define my rest services with minimal fuss.


So I started out with some Googling of GAE and REST. Support seemed overwhelmingly in favour of something called Restlet. Which with a bit of reading seemed to be a framework for creating REST services with Java. Plus it had a specific release for Google App Engine. Perfect!


Retlet didn’t have a “built for stupid” tutorial, so I've made my own. It’s loosely based on this intro



Start by downloading Restlet gae zip file and unzip




So lets use the backend project we created in my last tutorial




Create a libs directory under the root of backend.


Opening your unzipped Restlet folder to this directory restlet-gae-2.3.0\lib find the following two files:


  • org.restlet.ext.servlet.jar
  • org.restlet.jar


and copy them into your new libs directory and add this line to your gradle dependencies


compile fileTree(dir: 'libs', include: ['*.jar'])


Now add the following .java files to you backend package:
  • MyApplication
  • MyServerResource
  • NewServerResource


MyApplication.java
package com.example.myapplication.backend;

import org.restlet.Application;
import org.restlet.Restlet;
import org.restlet.routing.Router;

public class MyApplication extends Application {

    /**
     * Creates a root Restlet that will receive all incoming calls.
     */
    @Override
    public Restlet createInboundRoot() {
        // Create a router Restlet that routes each call to a
        // new instance of HelloWorldResource.
        Router router = new Router(getContext());

        // Defines only one route
        router.attachDefault(MyServerResource.class);
        //router.attach("/base/{username}", NewServerResource.class);
        //router.attach("/base", NewServerResource.class);

        return router;
    }
}
MyServerResource.java
package com.example.myapplication.backend;

import org.restlet.resource.Get;
import org.restlet.resource.ServerResource;

public class MyServerResource extends ServerResource{

    @Get
    public String represent(){
        return "Hello world";
    }
}
Now edit your web.xml file


webapp/WEB-INF/web.xml
<?xml version="1.0" encoding="utf-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee" version="2.5">
    <display-name>first steps servlet</display-name>

    <servlet>
        <servlet-name>SystemServiceServlet</servlet-name>
        <servlet-class>com.google.api.server.spi.SystemServiceServlet</servlet-class>
        <init-param>
            <param-name>services</param-name>
            <param-value>com.example.myapplication.backend.MyEndpoint</param-value>
        </init-param>
    </servlet>

    <servlet>
        <servlet-name>RestletServlet</servlet-name>
        <servlet-class>org.restlet.ext.servlet.ServerServlet</servlet-class>
        <init-param>
            <param-name>org.restlet.application</param-name>
            <param-value>com.example.myapplication.backend.MyApplication</param-value>
        </init-param>
    </servlet>

    <!-- Catch all requests -->
    <servlet-mapping>
        <servlet-name>SystemServiceServlet</servlet-name>
        <url-pattern>/_ah/spi/*</url-pattern>
    </servlet-mapping>
    <servlet-mapping>
        <servlet-name>RestletServlet</servlet-name>
        <url-pattern>/*</url-pattern>
    </servlet-mapping>
</web-app>

Note despite the Restlet tutorial I've left SystemServiceServlet in there. Ideally I’d want to remove this but GAE whines incessantly if you don’t have a servlet named SystemServiceServlet. Perhaps there’s a way to rename the RestletServlet but maybe one for another day.


That’s it. Now I shall try and explain a bit what’s going on. MyApplication is where the magic really happens, this is where we configure our REST urls. This line sets the default behaviour


router.attachDefault(MyServerResource.class);


Which if you open MyServerResource.java you’ll see it’s super simple it just says “hello world”. If you were to only include the attachDefault method (as above) you could happily run your app and http://localhost:8080/hippopotamus would return Hello world. This is a super simple GET request.


Fantastic! One job done.


Now Let’s make it a big more complicated. Let’s add a GET method with a param and a POST method. (un-comment the two router.attach lines in myApplication).


NewServerResource.java
package com.example.myapplication.backend;

import org.restlet.data.Form;
import org.restlet.representation.Representation;
import org.restlet.resource.Get;
import org.restlet.resource.Post;
import org.restlet.resource.ServerResource;


public class NewServerResource extends ServerResource{

    @Get
    public String restGetMethod(){

        String username  = "";
        try{
            //get param from request
            username = getRequest().getAttributes().get("username").toString();

        }catch(Exception e){
            username = "default";
        }

        return "Dear " + username + ". All your base are belong to me!";
    }

    @Post
    public String restPostMethod(Representation r){

        String username = "";

        //Get form details
        final Form form = new Form(r);

        //get username field out of form
        username = form.getFirstValue("username");

        return "Morning " + username + ". I've had it with all these snakes on the plane.";
    }
}

So a bit more complicated. The first is a @Get method which looks for a username param and returns “Dear username. All your base are belong to me!”


The second is based on a POST method. Here we’re grabbing the Form object and requests a value for the field username. It returns “Morning username. I've had it with all these snakes on the plane.”


So lets take a look how we pass these params to these methods back in MyApplication.


router.attachDefault(MyServerResource.class);
router.attach("/base/{username}", NewServerResource.class);
router.attach("/base", NewServerResource.class);


When you use router.attach you need to give it a url. So you can see here if we pass localhost:8080/base/gonzo then we’ll hit NewServerResource with the param username=gonzo. This is out GET request.


If we pass /base we’ll hit NewServerResource without any params. This will be our POST request.


So to summarize here are the responses we can expect to see from various REST urls:










Lastly to test the POST I’ve constructed a little form
<html>
    <head>
        <title>Post test</title>
    </head>
    <body>
        <p>Hello this is a post test for localhost</p>
        <br />
        <form action="http://localhost:8080/base" method="POST">
            <input name="username" type="text" />
            <button name="submit" type="submit" value="submit">Submit</button>
        </form>
    </body>
</html>

Note the input box. If we fill that in and submit we get this:


Morning Kermit. I've had it with all these snakes on the plane.


Fantastic, exactly what we wanted.


This is great, I’m delighted, a very easy way to get REST running on the cloud. Good work to all the chaps at Restlet, great little product and I feel like I’m only scratching the surface.

No comments: