Sunday, January 4, 2015

Releasing base-api, a Template for Scala API Server Development

After about the fourth or fifth time I sat down to write an API in Scala it occurred to me that I should probably create a template that has most of the common ingredients to a successful service. Having done so I am now posting it publicly in the off chance that it can help somebody else out. If not at least I get one of my private repos back ;)

Here are the primary features of base-api:

  • A layered project hierarchy that looks like: 
    • common libs => storage layer => business logic => public APIs
  • Clean, Scala-based build definition (as opposed to sbt-file based)
  • Slick 2.1 RDBMS integration (Postgres by default for prod, H2 for test)
    • Separate slick codegen project for automated DB abstraction case class generation
  • Redis KV Scala abstraction built on Sam Pullara's ultra-fast Java Redis client
  • Spray 1.3 REST API infrastructure
  • Netty 4.0 Socket API infrastructure
  • Json4s 3.2 json abstraction
  • Akka 2.3 actors for core business logic, Slf4j logging
  • Scalastyle 0.6 linting with some actually reasonable defaults configured
  • Scoverage 0.99 for code coverage (which is very high btw)
  • Scalariform 1.3 for code formatting (impossible to live without these days)
  • Sbt-Assembly for fat-jar creation
  • A nice clean homegrown abstraction on Typesafe Configs for service configuration
  • The basics of a user authentication and authorization scheme compatible with both the REST and Socket APIs simultaneously. Also includes API key-based authentication.
  • Permissions management functionality for API endpoints (again compatible with both APIs)
  • Probably a bunch of other cool junk I'm just failing to remember right now
  • MIT License
In a future posts I'd like to cover the abstraction on the Redis client, the Typesafe Config wrapper, the architecture for multiple APIs types built on the same business logic, and the philosophy behind all the build tools (linting, formatting, coverage, etc). In the meantime I'll just tease the config stuff since it's neat - here's an example service implementation interface:
    class CommonServiceImpl(
      akkaHost: String,
      akkaPort: Int,
      defaultDuration: FiniteDuration
    ) extends ServiceImpl with CommonService
And here's the entirety of the code needed to configure it from the reference conf:
    val AKKA = "akka"

    Services.register(new CommonServiceImpl(
      Keys(AKKA, "host"),
      Keys(AKKA, "port"),
      Keys(AKKA, "defaultTimeout")
    ))
Pretty cool huh.