Skip to content

Build a R-JSON web service using Rook and rjson

August 19, 2013

There have been lots of discussions on setting up a web server using Rook. But I haven’t found a complete sample on building a R based JSON web service. Whiling developing MyCaseTracker 2.0, I tried to implement a R-Rook-rjson setup of a RPC type web service.

Starting with setting up the web server environment under Rook.. If you want to just implement a simple localized (only bind to 127.0.0.1) web server, it is quiet easy by the following 4-step setup

> library(Rook)
> s <- Rhttpd$new()
> s$start(quiet=TRUE)
> s$print()

However, if you want to bind it to some IP address other than loopback, you will need some more work to do. Here is my example,

#server parameters
myPort <- 8000
myInterface <- "0.0.0.0"
status <- -1
# R 2.15.1 uses .Internal, but the next release of R will use a .Call.
# Either way it starts the web server.
if (as.integer(R.version[["svn rev"]]) > 59600) {
  status <- .Call(tools:::startHTTPD, myInterface, myPort)
} else {
  status <- .Internal(startHTTPD(myInterface, myPort))
}
if (status == 0) {
  unlockBinding("httpdPort", environment(tools:::startDynamicHelp))
  assign("httpdPort", myPort, environment(tools:::startDynamicHelp))
  s <- Rhttpd$new()
  s$listenAddr <- myInterface
  s$listenPort <- myPort
# Change this line to your own application. You can add more than one
# application if you like
  s$add(name = "test", app = Rook.app)
# Now make the console go to sleep. Of course the web server will still be running.
  while (TRUE) Sys.sleep(24 * 60 * 60)
}

The function Rook.app() is called everytime when a HTTP request is made.

Rook.app <- function(env) {
  request <- Request$new(env);
  response <- Response$new();
  write.initial.HTML(request,response);
  response$finish();
}

Request contains HTTP request information, you can parse GET, POST and etc to R.. Response is the output HTML to be returned.
In the sample above, Rook.app will call write.initial.HTML(request,response) to process the HTML request. You can write your JSON statements in there.

write.initial.HTML <- function(request,response, iter) {
  json_parser <- newJSONParser()
  json_parser$addData( request$GET()$p )
  rpc <- try( json_parser$getObject(), silent = TRUE );
  response$header('"Content-Type": "application/json"')
  if( class( rpc ) == "try-error" ) {
    response$write("not a valid json");
  }
  else {
    response$write(print(do.rpc(rpc)));
  }
}

You will need to load rjson library first. In the sample above, I used the GET statement and variable name is p. So your URL is something like http://webserver/custom/test?p={JSON DATA}. “/custom/test” is defined by Rook. rpc is the json parser from the URL request.

From here, I am going to use an example RPC to explain how rjson works with Rook. My function do.rpc() is follows.
# JSON processer:: do.rpc
do.rpc <- function( rpc )
{
  rpc$params <- as.list( rpc$params )
  result <- try( do.call( rpc$method, rpc$params ), silent = TRUE )
  if( class( result ) == "try-error" ) {
    #TODO JSON-RPC defines several erorrs (call not found, invalid params, and server error)
    #if a call exists but fails, I am sending a procedure not found - when really it was found
    #but had an internal error. the data contains the actual error from R
    rpc_result <- list(
      jsonrpc = "2.0",
      error = list( code = -32601, message = "Procedure not found.", data = as.character( result ) ),
      status = 500
    )
  } else {
    #RPC call suceeded
    rpc_result <- list(
      jsonrpc = "2.0",
      result = result,
      status = "success"
    );
  }
#return the JSON string
  ret <- toJSON( rpc_result );
  ret <- paste( ret, "\n", sep="" );
  return( ret );
}

In this RPC, rpc$method, rpc$params are the two parameters to be included in JSON request. You can do it using
http://webserver/custom/test?p={“method”:”myfunc”,”params”,”this is a test”}
or if you have more than one parameter to parse, you can use
http://webserver/custom/test?p={“method”:”myfunc”,”params”,[“first parameter”,”second parameter”,”third parameter”]}

In executing do.rpc(), it will call the function defined by rpc$method (“myfunc” from the sample url above). In this case, you can write as many functions and use the same do.rpc() to call.

Hope this helps you to setup your own R-Rook-JSON RPC server.

Advertisements

From → Engine

Leave a Comment

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: