The scala service framework inspired by Sinatra powered by twitter-server
.
Current version: 2.0.0.M1
Documentation for prior versions can be found here.
- Significant performance improvements over v1.6.0
- Powerful feature and integration test support
- JSR-330 Dependency Injection using Google Guice
- Jackson based JSON parsing with additional support for required fields, default values, and custom validations
- Logback MDC integration with com.twitter.util.Local for contextual logging across futures
We are publishing Scala 2.10 and 2.11 compatible libraries to Maven central. The Finatra project is currently split up into multiple components: (Inject and Finatra HTTP libraries).
Inject provides libraries for integrating twitter-server
and util-app
with Google Guice.
inject-core
inject-app
inject-server
inject-modules
inject-thrift-client
inject-request-scope
finatra-http
finatra-jackson
finatra-logback
finatra-httpclient
finatra-utils
To get started we'll focus on building an HTTP API for a simple "Todo" list application which will support adding tasks to a todo list. The full example can be found here.
First, we define our TaskRequest
domain object:
import com.twitter.finatra.validation.{NotEmpty, Size}
case class TaskRequest(
@NotEmpty name: String,
@Size(min = 10, max = 140) description: String)
Then, assuming we already have a TaskRepository
(configured with a TaskRepositoryModule
) to store tasks, let's create a Controller
:
import com.twitter.finagle.http.Request
import com.twitter.finatra.http.Controller
import com.twitter.todo.domain.{Task, GetTaskRequest, PostTaskRequest, TaskRepository}
import javax.inject.{Inject, Singleton}
@Singleton
class TasksController @Inject()(
repository: TaskRepository)
extends Controller {
post("/todo/tasks") { request: TaskRequest =>
val task = repository.add(request.name, request.description)
response
.created(task)
.location(task.id)
}
}
Next, let's create a HttpServer:
import com.twitter.finatra.http.HttpServer
import com.twitter.finatra.http.filters.CommonFilters
import com.twitter.finatra.http.routing.HttpRouter
import com.twitter.todo.modules.TaskRepositoryModule
class TodoServer extends HttpServer {
override val modules = Seq(
TaskRepositoryModule)
override def configureHttp(router: HttpRouter) {
router
.filter[CommonFilters]
.add[TasksController]
}
}
And finally, we can write a Feature Test:
import com.twitter.finagle.http.Status.{Created, BadRequest}
import com.twitter.finatra.http.test.EmbeddedHttpServer
import com.twitter.inject.server.FeatureTest
import com.twitter.todo.domain.Task
class TodoFeatureTest extends FeatureTest {
override val server = new EmbeddedHttpServer(new TodoServer)
"post good task" in {
server.httpPost(
"/todo/tasks",
"""
{
"name": "my-task",
"description": "pick up milk"
}
""",
andExpect = Created)
}
"post bad task" in {
server.httpPost(
"/todo/tasks",
"""
{
"name": "",
"description": "short"
}
""",
andExpect = BadRequest,
withJsonBody =
"""
{
"errors": [
"name cannot be empty",
"description size [5] is not between 10 and 140"
]
}
""")
}
}
- Steve Cosenza https://github.com/scosenza
- Christopher Coco https://github.com/cacoco
- Jason Carey https://github.com/jcarey03
- Eugene Ma https://github.com/edma2
A full list of contributors can be found on GitHub.
Follow @finatra on Twitter for updates.
Copyright 2015 Twitter, Inc.
Licensed under the Apache License, Version 2.0: http://www.apache.org/licenses/LICENSE-2.0