Coder Social home page Coder Social logo

twitter / finatra Goto Github PK

View Code? Open in Web Editor NEW
2.3K 214.0 406.0 32.63 MB

Fast, testable, Scala services built on TwitterServer and Finagle

Home Page: https://twitter.github.io/finatra/

License: Apache License 2.0

Shell 0.08% Java 5.27% Scala 87.52% HTML 0.01% Thrift 0.22% Starlark 6.88% Mustache 0.04%
scala finagle twitter-server http framework microservices thrift guice slf4j testing

finatra's Introduction

Finatra

Build Status Project status Maven Central Gitter

Status

This project is used in production at Twitter (and many other organizations), and is being actively developed and maintained.

Finatra Logo

Finatra is a lightweight framework for building fast, testable, scala applications on top of TwitterServer and Finagle. Finatra provides an easy-to-use API for creating and testing Finagle servers and apps as well as powerful JSON support, modern logging via SLF4J, Finagle client utilities, and more.

Getting involved

Features

Documentation

To get started, see the Getting Started section of our User Guide to get up and running. Or check out the specific sections for building HTTP or Thrift servers.

Examples

An HTTP controller and server:

import com.twitter.finatra.http._

@Singleton
class ExampleController extends Controller {
  get("/") { request: Request =>
    "<h1>Hello, world!</h1>"
  }
}
import com.twitter.finatra.http._

class ExampleServer extends HttpServer {
  override def configureHttp(router: HttpRouter): Unit = {
    router
      .filter[CommonFilters]
      .add[ExampleController]
  }
}

A Thrift controller and server:

import com.twitter.finatra.thrift._
import com.twitter.scrooge.{Request, Response}

@Singleton
class ExampleThriftController
  extends Controller(MyThriftService) {

  handle(MyFunction).withFn { request: Request[MyFunction.Args] =>
    ...
  }
}
import com.twitter.finatra.thrift._

class ExampleServer extends ThriftServer {
  override def configureThrift(router: ThriftRouter): Unit = {
    router
      .add[ExampleThriftController]
  }
}

Example Projects

Finatra includes working examples which highlight various features of the framework and include tests. These examples are included in the root sbt build and are thus buildable as part of the entire project.

Please take a look through the examples for more detailed information on features, testing, building, and running.

Latest version

The release branch in Github tracks the latest stable release, which is currently:

Maven Central

available on Maven Central. See the First Steps section in the User Guide for how to add dependencies.

Releases are done on an approximately monthly schedule. While semver is not followed, the changelogs are detailed and include sections on public API breaks and changes in runtime behavior.

Development version

The develop branch in Github tracks the latest code which is updated every week. If you want to contribute a patch or fix, please use this branch as the basis of your Pull Request.

We feel that a welcoming community is important and we ask that you follow Twitter's Open Source Code of Conduct in all interactions with the community. For more information on providing contributions, please see our CONTRIBUTING.md documentation.

Presentations

Check out our list of presentations: Finatra Presentations.

Authors

A full list of contributors can be found on GitHub.

Follow @finatra on Twitter for updates.

License

Copyright 2013 Twitter, Inc.

Licensed under the Apache License, Version 2.0: https://www.apache.org/licenses/LICENSE-2.0

finatra's People

Contributors

armandocanals avatar cacoco avatar capotej avatar chrisbenincasa avatar dotordogh avatar edma2 avatar enbnt avatar grimreaper avatar hamdiallam avatar isabelmartin avatar jcrossley avatar joybestourous avatar jyanjing avatar kevinoliver avatar luciferous avatar mattdickinson5 avatar mosesn avatar nepthar avatar patliu85 avatar pcalcado avatar ryanoneill avatar sameerparekh avatar scosenza avatar sideshowcoder avatar tigerlily-he avatar twoism avatar vkostyukov avatar wisechengyi avatar xorlev avatar yufangong avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

finatra's Issues

Startup / Shutdown hooks

E.g. initialize / shutdown a redis connection pool. I didn't see a place to put these. Many require a call for the threadpool to be shutdown for the app to exit cleanly.

I suppose one could put stuff on a singleton object, that the controller could access, and have the thing that starts up FinatraServer manage starting up and shutting down the stuff that lives there?

libthrift outdated

I just saw that the project are using libthrift 0.5.0, and the last version is 0.9.1.

Version 0.5.0 isn't available in commom mvn repos, only at twitter mvn repo.

There should not be an issue at all, but, I'm under a corporate proxy with all sort of funny things that a MS-based network can provide, and we also have a nexus mirror. This nexus mirrors seems to not been able to mirror the twitter repo.

Is there any special reason for finatra not use the lastest version of libthrift?

Thanks!

Sending redirect require a body

Doing this:

render.status(HttpResponseStatus.MOVED_PERMANENTLY.getCode).header("Location", redirectUrl).toFuture

does not work because of the missing body. Responds with a 500 instead.

LogLevel doesn't seem to work

Hi!

I've tried to set the logging level to DEBUG and WARNING or ERROR by

  1. using the flag: -com.twitter.finatra.config.logLevel='ERROR' or
  2. setting System.setProperty("com.twitter.finatra.config.logLevel", "DEBUG") before registering the controllers

However, I always seem to have info messages coming through and never debug. If I call log.getLevel, I always get null.

Maybe I'm doing something wrong and I'm stuck. BTW, the documentation about the flags is wrong: it's not -usage but -help seems to work :-)

Unable to retrieve post parameters

I'm unable to retrieve post parameters to handle the form submit.

Here is a simple app that reproduces the problem

object Main {

  class ExampleApp extends Controller {

    post("/param") {
      request =>
        request.params.get("test") match {
          case Some(value) => render.plain(value.toString).status(200).toFuture
          case None => render.plain("No param").status(404).toFuture
        }
    }

  }


  def main(args: Array[String]) {
    val app = new ExampleApp

    FinatraServer.register(app)
    FinatraServer.start()

  }

}

When I execute

curl -iH 'Content-Type: application/x-www-form-urlencoded' -XPOST http://localhost:7070/param -d 'test=myparam'

I get no param response

HTTP/1.1 404 Not Found
Content-Type: text/plain
Content-Length: 8

No param

RequestAdapter does not support multiple values for query params

If you want to send an array as query parameters to a GET request, jQuery encodes it as follows

var a = {key: [1,2,3]}
$.param(a) // key[]=1&key[]=2&key[]=3

For nested hashes:

var b = {key1: {field1:1, field2: 2}, key2: {field1: 2, field2: 89}}
$.param(b) // key1[field1]=1&key1[field2]=2&key2[field1]=2&key2[field2]=89

There can obviously be some pretty complicated nesting of these.

Currently Finatra only pulls the head off a set of query parameters that all have the same key (first example would give only one of them). It would be nice to return the set of all values, otherwise it requires a bit of application logic/coordination to figure out which keys are actually present.

https://github.com/capotej/finatra/blob/master/src/main/scala/com/twitter/finatra/RequestAdapter.scala#L39

Filter invoked 4 times per single request?

Using the ugly patch described previously, I've added a single filter to the application. When tracing the filter, I see that it gets invoked 4 times per http request. I've verified that I'm indeed only making 1 http request and not 4. Any idea what's going on here?

Here's a fragment of a stack trace that I captured that shows the caller of the filter:

com.twitter.finagle.Filter$$anon$2.apply(Filter.scala:69)
com.twitter.finagle.Service$$anon$1.apply(Service.scala:14)
com.twitter.finatra.FileService.apply(FileService.scala:121)
com.twitter.finatra.FileService.apply(FileService.scala:85)
com.twitter.finagle.Filter$$anon$2.apply(Filter.scala:69)
com.twitter.finagle.Service$$anon$1.apply(Service.scala:14)
com.twitter.finatra.LoggingFilter.apply(LoggingFilter.scala:11)
com.twitter.finatra.LoggingFilter.apply(LoggingFilter.scala:8)
com.twitter.finagle.Filter$$anon$2.apply(Filter.scala:69)
com.twitter.finagle.Service$$anon$1.apply(Service.scala:14)
com.twitter.finagle.Service$$anon$1.apply(Service.scala:11)
com.twitter.finatra.FinatraServer$$anonfun$2.apply(FinatraServer.scala:59)
com.twitter.finatra.FinatraServer$$anonfun$2.apply(FinatraServer.scala:58)
com.twitter.finagle.Filter$$anon$6.apply(Filter.scala:117)
com.twitter.finagle.Filter$$anon$2.apply(Filter.scala:69)
com.twitter.finagle.ServiceProxy.apply(Service.scala:103)
com.twitter.finagle.Service$$anon$1.apply(Service.scala:14)
com.twitter.finagle.Filter$$anon$4.apply(Filter.scala:111)
com.twitter.finagle.Filter$$anon$5$$anon$1.apply(Filter.scala:53)
com.twitter.finagle.service.StatsFilter.apply(StatsFilter.scala:34)
com.twitter.finagle.Filter$$anon$5.apply(Filter.scala:52)
com.twitter.finagle.Filter$$anon$2.apply(Filter.scala:69)
com.twitter.finagle.Service$$anon$1.apply(Service.scala:14)
com.twitter.finagle.tracing.ServerDestTracingProxy$$anon$1.apply(DestinationTracing.scala:26)
com.twitter.finagle.Filter$$anon$2.apply(Filter.scala:69)
com.twitter.finagle.Service$$anon$1.apply(Service.scala:14)
com.twitter.finagle.filter.MkJvmFilter$$anon$1.apply(JvmFilter.scala:29)
com.twitter.finagle.Filter$$anon$5$$anon$1.apply(Filter.scala:53)
com.twitter.finagle.tracing.TracingFilter$$anonfun$apply$1.apply(TracingFilter.scala:18)
com.twitter.finagle.tracing.TracingFilter$$anonfun$apply$1.apply(TracingFilter.scala:16)
com.twitter.finagle.tracing.Trace$.unwind(Trace.scala:183)
com.twitter.finagle.tracing.TracingFilter.apply(TracingFilter.scala:16)
com.twitter.finagle.Filter$$anon$5$$anon$1.apply(Filter.scala:53)
com.twitter.finagle.filter.MonitorFilter$$anonfun$apply$1.apply(MonitorFilter.scala:16)
com.twitter.finagle.filter.MonitorFilter$$anonfun$apply$1.apply(MonitorFilter.scala:16)
com.twitter.util.Future$$anonfun$monitored$1.apply$mcV$sp(Future.scala:93)
com.twitter.util.Monitor$$anonfun$apply$1.apply$mcV$sp(Monitor.scala:38)
com.twitter.util.Monitor$$anonfun$apply$1.apply(Monitor.scala:38)
com.twitter.util.Monitor$$anonfun$apply$1.apply(Monitor.scala:38)
com.twitter.util.Monitor$$anonfun$using$1.apply(Monitor.scala:103)
com.twitter.util.Monitor$.restoring(Monitor.scala:110)
com.twitter.util.Monitor$.using(Monitor.scala:101)
com.twitter.util.Monitor$class.apply(Monitor.scala:37)
com.twitter.util.Monitor$$anon$1.apply(Monitor.scala:141)
com.twitter.util.Future$.monitored(Future.scala:92)
com.twitter.finagle.filter.MonitorFilter.apply(MonitorFilter.scala:15)
com.twitter.finagle.Filter$$anon$5$$anon$1.apply(Filter.scala:53)
com.twitter.finagle.filter.HandletimeFilter.apply(HandletimeFilter.scala:15)
com.twitter.finagle.Filter$$anon$5.apply(Filter.scala:52)
com.twitter.finagle.Filter$$anon$5.apply(Filter.scala:52)
com.twitter.finagle.Filter$$anon$5.apply(Filter.scala:52)
com.twitter.finagle.Filter$$anon$2.apply(Filter.scala:69)

Filters not working

Hey, I'm using the latest version of finatra, but it seem that filters are not working as described here:

http://finatra.info/docs/index.html#filters

I built a single file example with a filter that throws an exception to isolate the problem:

package com.fintest

import com.twitter.finatra._
import com.twitter.finagle._
import com.twitter.app.App
import com.twitter.finagle.http.{Request => FinagleRequest}
import com.twitter.finagle.http.{Response => FinagleResponse}

class Example extends Controller {
  get("/") { request =>
     render.plain("hi").toFuture
  }
}

class MyServer extends FinatraServer {
    val controller = new Example()
    addFilter(new TestFilter)
    register(controller)
}

class TestFilter extends SimpleFilter[FinagleRequest, FinagleResponse] with App {

  def apply(
    request: FinagleRequest,
    service: Service[FinagleRequest, FinagleResponse]) = {
    service(request) map { response =>
        throw new Exception("!") // this is never executed
        response
    }
  }
}

object Runner {
    def main(args: Array[String]): Unit = {
        val server = new MyServer()
        server.start()
    }  
}

The exception is never thrown. Any idea why this is the case?

filters for select routes only

Is it currently possible to apply filters just to select routes? For instance if I don't want a filter to run on every static file that's served. I'm sure I can figure out a way to hack this together in my own app logic but am wondering if there is anything that I could use out of the box.

thanks!

Serve static files

There should be a possibility to serve static resources

  • Images
  • CSS files
  • JS files
  • etc.

Custom error handlers

There should be a possibility to define custom error handler for specified exception.

Right now it is possible to define custom filter as a workaround but this could be simplified.

maven => sbt

sbt is the de facto build tool in scala-land, finatra should probably use it.

Make mustache factory use baseTemplatePath local_docroot and template_path

I have a couple of mustache files stored in resources/mustache. I have set -Dlocal_docroot=resources and -Dtemplate_path=mustache/ when running my finatra server.

Whenever I load a partial (which is in the resources/mustache directory) i need to prefix the partial name with mustache/ in the file that loads the partial. I'd expect to be able to do

{{> my_partial.mustache}}

instead of having to do

{{> mustache/my_partial.mustache}}

Is this expected behavior, or is there a bug on my end? Should this be changed? If so I can come up with a patch.

request.routeParams should be decoded

When requesting /hello%3Aworld?bar=hello%3Aworld

get("/:foo") { request =>
    request.routeParams.get("foo").get should equal("hello:world") // it's actually `hello%3Aworld`
    request.params.get("bar").get should equal("hello:world")
}

Workaround:

import org.jboss.netty.handler.codec.http.QueryStringDecoder
import org.jboss.netty.util.CharsetUtil

QueryStringDecoder.decodeComponent(param, CharsetUtil.UTF_8)

using websockets

Hi..is there any tutorial or explanation of how use websockets with finatra?...is possible use atmosphere websocket with finatra similar to scalatra or many others frameworks??...thanks!!

Test/Harden logging

We seem to always mess up logging, let's get some tests around this to ensure high quality logging.

Test Cases:

  • Log levels are respected
  • Ability to turn off logging

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.