Implementing a modern API design on Typetalk

play_thumb
In my previous blog post, I’ve introduced how the Typetalk API takes an important role in its architecture. Here, I’d like to share how we realize it in some snippets of code. Since we are using Playframework and Scala, the examples here are written in Scala and use Playframework features as well.
First, define Account model and Auth trait used by both web and API controllers like this:
case class Account(id: Long, name: String)

trait Auth {
  def authorizedAction(block: Account => Request[AnyContent] => SimpleResult): Action[AnyContent]
}

In this example (and in our actual production code), we pass “block”  to authorizedActionmethod and the “block” is a callback that should be invoked with theAccountandRequestobjects after theAccountinformation is properly retrieved.  You can change this trait definition according to your project design. For example, you can make wrapper request with the account information and pass it to the callback.

If you are using Playframework 2.2, you may be able to useActionBuilder. The Playframework site provides some resolutions about Action composition:
TheauthorizedAction implementation is shared among endpoints for Web and API respectively.
We are manually making an account instance here. In your production however, you will have to restore such info through your backend authorization system properly and also handle error if the restoration fails.
trait WebAuth extends Auth {
  def authorizedAction(block: Account => Request[AnyContent] => SimpleResult): Action[AnyContent] = Action { implicit request =>
    val account = Account(1, "web") // TODO find account by session or etc
    block(account)(request)
  }
}
 
trait APIAuth extends Auth {
  def authorizedAction(block: Account => Request[AnyContent] => SimpleResult): Action[AnyContent] = Action { implicit request =>
    val account = Account(2, "api") // TODO find account by OAuth or etc
    block(account)(request)
  }
}
The next step includes defining a controller to use both Web and API, and just only returning account model to serialize json in this case.
package controllers
 
import play.api._
import play.api.mvc._
import play.api.libs.json._
 
trait AccountController extends Controller {
 
  self: Auth =>
 
  def signedInAccount = authorizedAction { account => implicit request =>
    Ok(Json.obj(
      "id" -> account.id,
      "name" -> account.name
    ))
  }
}
You can find a little strange notation, self: Auth =>, in the code above. This is called “Self-Type Annotations” in Scala. Here, the Self-Type annotations ensure that the controller will eventually have theAuth trait or its sub-trait in its implementation class so that this controller can call the methodauthorizedAction defined inAuth trait without any explicit declaration of its concrete class.
This enables us to offer same functionalities for both Web and API by just switchingAuth trait for the respective controllers as follows:
object AccountWebController extends AccountController with WebAuth
object AccountApiController extends AccountController with APIAuth
What a sweet feature Scala has! You can now define routing to each controller methods:
GET     /api/account.json           controllers.AccountApiController.signedinAccount
GET     /account.json               controllers.AccountWebController.signedinAccount
Access each url.
$ curl http://localhost:9000/account.json
{"id":1,"name":"web"}
 
$ curl http://localhost:9000/api/account.json
{"id":2,"name":"api"}
The above is a good response. Both expected processing were executed.
As you can see here,signedInAccount implementation is shared among both controllers.
If you want to render html for only web then it’s fine to just define only Web controller usingWebAuth.
object AccountWebController extends AccountController with WebAuth {
  def render = authorizedAction { account => implicit request =>
    Ok(views.html.account(account)
  }
}
Conversely, if you want to provide only API then you just only need to write API controller usingAPIAuth. This allows us to respond flexibly.
The great features and flexibility of Scala and Playframework make it really simple to implement to modern API design. I have published this sample code on Github. Feel free to share any comments or feedback below in the comment section.