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.

22 January 2015

Google App Engine and Android playing nice.

I'm a big fan of cloud services, especially when they give you a free or basic quota such as Google App Engine which you can use for development or testing. I’ve done quite a bit of work with Google App Engine before but not in a while. It became a real heavy beast involving importing add ons to Eclipse and configuring a multitude of environment settings.

However recently I've moved to Android Studio and apparently Google Cloud support is built in. Learning this I was then inspired by a recent post on the Android Developers Blog:
http://android-developers.blogspot.co.uk/2014/12/build-mobile-app-services-with-google.html

I felt this wasn't a great tutorial, there were large sections left out and it basically didn't work nearly as easily as I’d hoped it would. Sorry Android Developers, but not your best work. Still the steps to get started were simple enough:
  1. Create a super simple Android app. Basic Hello world stuff.
  2. Give your app Internet permissions
  3. Create a new Google Cloud Module
    • File -> New Module
    • Click “Google Cloud Module”
    • Select App Engine Java Endpoints Module
Android studio will now create a GAE backend module for you and automatically tie it into your Android app. Now you need a bean and an endpoint.

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

public class MyBean {

    private String myData;

    public String getData() {
        return myData;
    }

    public void setData(String data) {
        myData = data;
    }
}


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

import com.google.api.server.spi.config.Api;
import com.google.api.server.spi.config.ApiMethod;
import com.google.api.server.spi.config.ApiNamespace;

import javax.inject.Named;

/**
 * An endpoint class we are exposing
 */
@Api(name = "myApi", version = "v1", namespace = @ApiNamespace(ownerDomain = "backend.myapplication.example.com", ownerName = "backend.myapplication.example.com", packagePath = ""))
public class MyEndpoint {

    /**
     * A simple endpoint method that takes a name and says Hi back
     */
    @ApiMethod(name = "sayHi")
    public MyBean sayHi(@Named("name") String name) {
        MyBean response = new MyBean();
        response.setData("Hi, " + name);

        return response;
    }

}
and here’s the Gradle file:

buildscript {
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath 'com.google.appengine:gradle-appengine-plugin:1.9.14'
    }
}

repositories {
    mavenCentral();
}

apply plugin: 'java'
apply plugin: 'war'
apply plugin: 'appengine'

sourceCompatibility = JavaVersion.VERSION_1_7
targetCompatibility = JavaVersion.VERSION_1_7

dependencies {
    appengineSdk 'com.google.appengine:appengine-java-sdk:1.9.14'
    compile 'com.google.appengine:appengine-endpoints:1.9.14'
    compile 'com.google.appengine:appengine-endpoints-deps:1.9.14'
    compile 'javax.servlet:servlet-api:2.5'
}

appengine {
    downloadSdk = true
    appcfg {
        oauth2 = true
    }
    endpoints {
        getClientLibsOnBuild = true
        getDiscoveryDocsOnBuild = true
    }
}


Frustratingly you’ll get red errors all over the place. Cannot resolve symbol api. This really winds me up and I’ve not yet figured out how to fix it. However it does build and run with these problems, so not really an error!

If you change the run drop down to “backend” and hit run hopefully this will all compile and you’ll get an Android Studio message with a localhost url. This is Android Studio setting up a local version of Google App Engine and using Jetty to host it. You should see a url output which you can copy to your browser, something like:
http://localhost:8080/

Hitting this url you should get an index file saying Hello Endpoints or something with a nice pretty bootstrap wrapper. You can enter something into the text field and your GAE application will say Hi to you.

Now we need to plug this into our Android app. First we need a new AsyncTask

package tester.example.com.myapplication;

import android.content.Context;
import android.os.AsyncTask;
import android.support.v4.util.Pair;
import android.widget.Toast;

import com.example.myapplication.backend.myApi.MyApi;

import com.google.api.client.extensions.android.http.AndroidHttp;
import com.google.api.client.extensions.android.json.AndroidJsonFactory;
import com.google.api.client.googleapis.services.AbstractGoogleClientRequest;
import com.google.api.client.googleapis.services.GoogleClientRequestInitializer;


import java.io.IOException;

class EndpointsAsyncTask extends AsyncTask<Pair<Context, String>, Void, String> {
    private static MyApi myApiService = null;
    private Context context;

    @Override
    protected String doInBackground(Pair<Context, String>... params) {
        if(myApiService == null) {  // Only do this once
            MyApi.Builder builder = new MyApi.Builder(AndroidHttp.newCompatibleTransport(),
                    new AndroidJsonFactory(), null)
                    // options for running against local devappserver
                    // - 10.0.2.2 is localhost's IP address in Android emulator
                    // - turn off compression when running against local devappserver
                    .setRootUrl("http://10.0.2.2:8080/_ah/api/")
                    .setGoogleClientRequestInitializer(new GoogleClientRequestInitializer() {
                        @Override
                        public void initialize(AbstractGoogleClientRequest<?> abstractGoogleClientRequest) throws IOException {
                            abstractGoogleClientRequest.setDisableGZipContent(true);
                        }
                    });
            // end options for devappserver

            myApiService = builder.build();
        }

        context = params[0].first;
        String name = params[0].second;

        try {
            return myApiService.sayHi(name).execute().getData();
        } catch (IOException e) {
            return e.getMessage();
        }
    }

    @Override
    protected void onPostExecute(String result) {
        Toast.makeText(context, result, Toast.LENGTH_LONG).show();
    }
}
Now in your app activityMain or somewhere, fire a call to the AsyncTask:

new EndpointsAsyncTask().execute(new Pair(this, "Manfred"));

The dependencies in your Android app should look like this:

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile 'com.android.support:appcompat-v7:21.0.3'
    compile 'com.google.android.gms:play-services:6.1.71'
    compile project(path: ':backend', configuration: 'android-endpoints')
}

Now if you run your Android app in a Android Virtual Device, you should see your local server respond with a Hi Message.

This is a pretty basic example, but you get the idea and its a great first step on the path toward Android and Google Cloud playing well together.