Fast, testable, Scala services built on Twitter-Server and Finagle
- Production use as Twitter’s HTTP framework
- ~50 times faster than v1.6 in several benchmarks
- Powerful feature and integration test support
- Optional JSR-330 Dependency Injection using Google Guice
- Jackson based JSON parsing supporting required fields, default values, and custom validations
- Logback MDC integration with com.twitter.util.Local for contextual logging across futures
Check out our list of recent presentations: Finatra Presentations
- Finatra is now built against the latest Finagle v6.30.0 and Twitter Server v1.15.0 releases.
- Please take a look at our new User Guide!
- Keep up with the latest news here on our blog.
To get started we'll focus on building an HTTP API for posting and getting tweets:
case class TweetPostRequest(
@Size(min = 1, max = 140) message: String,
location: Option[TweetLocation],
nsfw: Boolean = false)
case class TweetGetRequest(
@RouteParam id: TweetId)
Then, let's create a Controller
:
@Singleton
class TweetsController @Inject()(
tweetsService: TweetsService)
extends Controller {
post("/tweet") { requestTweet: TweetPostRequest =>
for {
savedTweet <- tweetsService.save(requestTweet)
responseTweet = TweetResponse.fromDomain(savedTweet)
} yield {
response
.created(responseTweet)
.location(responseTweet.id)
}
}
get("/tweet/:id") { request: TweetGetRequest =>
tweetsService.getResponseTweet(request.id)
}
}
Next, let's create a server:
class TwitterCloneServer extends HttpServer {
override val modules = Seq(FirebaseHttpClientModule)
override def configureHttp(router: HttpRouter): Unit = {
router
.filter[CommonFilters]
.add[TweetsController]
}
}
And finally, we can write a Feature Test:
class TwitterCloneFeatureTest extends FeatureTest with Mockito {
override val server = new EmbeddedHttpServer(new TwitterCloneServer)
@Bind val firebaseClient = smartMock[FirebaseClient]
@Bind val idService = smartMock[IdService]
"tweet creation" in {
//Setup mocks
idService.getId returns Future(StatusId("123"))
val tweetResponse = TweetResponse(...)
firebaseClient.put("/tweets/123.json", tweetResponse) returns Future.Unit
firebaseClient.get("/tweets/123.json")(manifest[TweetResponse]) returns Future(Option(tweetResponse))
//Assert tweet post
val result = server.httpPost(
path = "/tweet",
postBody = """
{
"message": "Hello #FinagleCon",
"location": {
"lat": "37.7821120598956",
"long": "-122.400612831116"
},
"nsfw": false
}""",
andExpect = Created,
withJsonBody = """
{
"id": "123",
"message": "Hello #FinagleCon",
"location": {
"lat": "37.7821120598956",
"long": "-122.400612831116"
},
"nsfw": false
}""")
server.httpGetJson[TweetResponse](
path = result.location.get,
andExpect = Ok,
withJsonBody = result.contentString)
}
"Post bad tweet" in {
server.httpPost(
path = "/tweet",
postBody = """
{
"message": "",
"location": {
"lat": "9999"
},
"nsfw": "abc"
}""",
andExpect = BadRequest,
withJsonBody = """
{
"errors" : [
"message: size [0] is not between 1 and 140",
"location.lat: [9999.0] is not between -85 and 85",
"location.long: field is required",
"nsfw: 'abc' is not a valid boolean"
]
}
""")
}
}
The Finatra project is composed of several libraries. You can find details in a project's README or see the User Guide for detailed information on building applications with Finatra.
For more detailed information see the README.md within each example project.
A barebones "Hello World" service.
A barebones service that is deployable to Heroku.
A url shortening example that is deployable to Heroku.
An example Twitter-like API for creating and retrieving Tweets.
A server used for benchmarking performance compared to a raw finagle-http service.
A proof-of-concept streaming JSON service.
- Steve Cosenza https://github.com/scosenza
- Christopher Coco https://github.com/cacoco
- Jason Carey https://github.com/jcarey03
- Eugene Ma https://github.com/edma2
- Nikolaj Nielsen https://github.com/nhnFreespirit
- Alex Leong https://github.com/adleong
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