WYSIWYG

http://kufli.blogspot.com
http://github.com/karthik20522

Monday, August 19, 2013

Spray.io REST service - Exception, Rejection and Timeout Handling - Lesson 7

View the lessons list at https://github.com/karthik20522/SprayLearning

Handling exceptions with the application and returning a valid http response with message is probably the way to go for building readable REST Api's. In spray,exceptions thrown during route execution bubble up thru the route structure up to the next enclosing handleExceptions directive. If you’d like to customize the way certain exceptions are handled simply bring a custom ExceptionHandler into implicit scope of the runRoute wrapper. For example:

More information on Handling Exceptions can be found at spray-routing/key-concepts/exception-handling/

How about handling Rejections? Similar to handling exceptions we can handle rejections in similar fashion. In this example I have created a separate trait with the rejection handler. I came across an issue with some conflict with shapeless syntax and rejection handler syntax "::"
More information on Handling Rejections at spray-routing/key-concepts/rejections/

Timeout Handling: spray-routing itself does not perform any timeout checking, it relies on the underlying spray-can to watch for request timeouts. The timeout value is defined in the config file (application.conf) More information on Timeout Handler at spray-routing/key-concepts/timeout-handling/

Labels: ,

Sunday, August 18, 2013

Spray.io REST service - API Versioning - Lesson 6

View the lessons list at https://github.com/karthik20522/SprayLearning

Before we get into spray, would recommend reading different ways of Versioning an API or best practices of versioning an API at best-practices-for-api-versioning or versioning-rest-api.

To summarize the stackoverflow discussion, there are 3 ways to do versioning.
  • Header based - using X-API-Version
  • URL based - http://{uri}/v1/getCustomer
  • Content negotiation via Accept headers - application/vnd.example.v1+json (mediatype)
For this tutorial, I would be implementing the first two.

1) Header based - using X-API-Version Here I am building a Directive that extracts the version from the request header. If not exists than I am defaulting to 1 In the above code there are two keywords, "extract" and "provide". These are part of Sprays BasicDirective. "extract" basically allows you to extract a single value and "provides" allows you to inject a value into the Directive. But wait, we can make this trait even smaller by getting rid of the provide all together to something as follows: Note: there are more than one way to write same operation in scala/spray. bane of my existence!
More info at: spray/routing/directives/BasicDirectives.scala

Now that we have defined the directive, we just need to inherit the directive to service trait and call versioning to extract the version number from X-API-Version header field. 2) url based - http://{uri}/v1/getCustomer
Here we are basically performing regex on the incoming request.uri and extracting the version out of "v*". Spray provides quite a few PathFilters and one of them being PathMatcher. More info at:

Labels: ,

Saturday, August 17, 2013

Spray.io REST service - Authentication - Lesson 5

View the lessons list at https://github.com/karthik20522/SprayLearning

"Directives" are small building blocks of which you can construct arbitrarily complex route structures. A directive does one or more of the following:
  • Transform the incoming RequestContext before passing it on to its inner route
  • Filter the RequestContext according to some logic, i.e. only pass on certain requests and reject all others
  • Apply some logic to the incoming RequestContext and create objects that are made available to inner routes as "extractions"
  • Complete the request
More detailed information on directives can be found at http://spray.io/documentation/1.2-M8/ or here Spray-routing/predefined-directives-alphabetically/. In future examples, I would be using Directives so basic understanding would be useful. For this example I would be using Authentication directive to validate the request with a username and password as part of the header.

So, for authentication a new UserAuthentication trait is created which has a function that returns a ContextAuthenticator. The authenticate directive expects either a ContextAuthenticator or a Future[Authenication[T]]. At the crust of ContextAuthenticator is basically Future[Authenication[T]].

Below code that describes the authentication directive basically takes in a ContextAuthenticator and returns a Future of Authentication type of Either Rejection or an Object of type T. What this means is that Either a Rejection is returned (Left) like FailedAuthenticationRejection when credentials are missing or failed; or when successful an object is returned (Right)

The UserAuthentication trait has two functions, one that returns a ContextAuthentication and other that returns a Future. In this example, I am reading the username and password from the application.conf file and validating against it.
Note that I am importing "scala.concurrent.ExecutionContext.Implicits.global", this is because futures require an ExecutionContext and I letting spray to use the default actor ExecutingContext. //implicit val system = ActorSystem("on-spray-can")

Now that we have the authentication setup, we need to inherit the UserAuthenticationTrait using "with" and use the "authentication" directive by passing the "authenticateUser" function that we defined.


Further readings on this topic:
Spray/routing/authentication/HttpAuthenticator.scala
Spray/routing/SecurityDirectivesSpec.scala
https://groups.google.com/forum/#!topic/spray-user/5DBEZUXbjtw
Spray/routing/RejectionHandler.scala

Labels: , ,

Friday, August 16, 2013

Spray.io REST service - MongoDB - Lesson 4

View the lessons list at https://github.com/karthik20522/SprayLearning

Now that we have Spray Service Setup and Routes defined, we can now hookup the database to add and fetch customer information. For the database I am using MongoDB and Casbah. Casbah is a Scala toolkit for MongoDB. Casbah is a "toolkit" rather than "driver", as Casbah is a layer on top of the official mongo-java-driver for better integration with Scala.

To get Casbah setup, we need to add casbah and it's related dependencies to the Build.scala file.
Note that we have slf4j and scala logging in the dependencies. Without slf4j you would get "Failed to load class org.slf4j.impl.StaticLoggerBinder" error.

In my example, I have created a MongoFactory that has 3 functions: getConnection, getCollection and closeConnection.
Now that we have our Factory method, the next is building the data access class for inserting and fetching data. Following code snippet has 2 operations:
  • saveCustomer - which returns back the GUID after inserting into MongoDB
  • findCustomer - find customer by GUID
Now to integrate this to the service: More information and resources on Casbah:

Labels: , ,

Thursday, August 15, 2013

Spray.io REST service - Json Serialization, De-serialization - Lesson 3

View the lessons list at https://github.com/karthik20522/SprayLearning

For a REST based interface, JSON request and response is the norm. There are two ways to set the response format in Spray.

1) using respondWithMediaType In this method, each route/action would have to be explicitly set with media type of json. More info at https://github.com/spray/spray/wiki/Misc-Directives

2) Globally overriding the default format.

For all Json related operations, I am using Json4s as the json library. In the build.scala add the following json4s dependency. Note: you would need to reload the project in sbt and regenerate Eclipse. Eclipse does not refresh itself when new dependencies are added

In the CustomerServiceActor we will need to set the default Format to json4sFormats by adding the implicit formatter For example purpose, lets update the getCutomer action to return a mocked customer. The expected response should be a json formatted customer object.
To post a customer object and deserialize it to customer type, we can use spray entity [http://spray.io/documentation/1.1-M8/spray-httpx/unmarshalling/] and cast the post value to a JObject Further reading on json4s at https://github.com/json4s/json4s

Labels: ,

Spray.io REST service - Controller, Actions, Multiple controllers - Lesson 2

View the lessons list at https://github.com/karthik20522/SprayLearning

Once you have the Spray.io project setup (http://kufli.blogspot.com/2013/08/sprayio-rest-web-api-basic-setup.html) you can find the boot file and controller files in the "src/main/scala/com/example" folder path. There are two files that are of interest. One is the Boot.scala and other MyService.scala. Boot.scala is basically the placeholder to define the controller (single, multi controllers) and the http binding. Actions of these controllers are coded in the MyService.scala file.

In the following example, I am renaming the MyService.scala to a more meaningful service to CustomerService.scala. Before we start working on the project would like to generate the eclipse project files for the code to be edited on Eclipse rather than Sublime or any text editor.

To get it setup on eclipse, you can run the “eclipse” command within the sbt console. Note that, in plugins.sbt you should have sbteclipse plugin. View the initial project setup http://kufli.blogspot.com/2013/08/sprayio-rest-web-api-basic-setup.html

Following screenshot is the structure of the project within eclipse.



CustomerService.scala class:

This class basically is the controller class with Actions/routes defined in them. I personally like to separate the service behavior from service actor as we want to be able to test it independently without having to spin up an actor.
customerRoutes is the place holder where all the routes/actions are defined and implemented. An example of how routes look is as follows: The urls for accessing the above routes are as :

How about multiple controllers? It is as easy as creating a new trait extending HttpService and piping into the existing route. For example, if we want to create an Ajax service for all search related operations, following is a code snippet: The above project can be downloaded at https://github.com/karthik20522/SprayLearning

Labels: ,

Spray.io REST Web API - Basic setup

What is Spray: "spray is an open-source toolkit for building REST/HTTP-based integration layers on top of Scala and Akka. Being asynchronous, actor-based, fast, lightweight, modular and testable it's a great way to connect your Scala applications to the world". Basically spray is web framework for building REST based services similar to ASP.NET WebAPI. Spray can be used for hosting both a rest based service as well as web pages (static/dynamic)

To get spray up and running you can download the SprayTemplate project from Github.com/spray
Note: there are multiple branches of spray with different spray, akka and server versions. For this example I am using on_spray-can_1.2 branch which has spray-can (server). Scala 2.10, Akka 2.2 and Spray 1.2

Folder Setup:



There are two important files that one must be aware of.

1) build.sbt : this file contains basic information of your project like com name, version and scalaversion. But addition to that there is libraryDependencies which has a list of external/internal libraries that the project might use. For example, if we decide to use json4s library or a mongoDB library, this is the place we would be adding to.
If you notice in the libraryDependecies we have {"io.spray"%"spray-can"% "1.2-M8"}, this can be read as {“GroupId” %”DependencyName”%”Version”}. But what about double “%%”, this is basically letting sbt know to use the version that is compatible with the current version of scala that is being used.

These plugins can be located at maven repository at mvnrepository.com. An example dependency: http://mvnrepository.com/artifact/org.json4s/json4s-native_2.10/3.2.5

2) plugins.sbt: this file contains the plugins that sbt intends to use. Note that plugins.sbt requires an extra line break between the plugins. An example plugins.sbt looks like the following:



To run the project, in the project folder run the following commands:

The above project can be downloaded at https://github.com/karthik20522/SprayLearning

Labels: ,

Friday, August 9, 2013

Beers in my Belly - XX


Sculpin IPA

Jenlain ambree

Labels: