Scalatra 2.2.0-RC1 Released

Scalatra 2.2 has been in development for about the past two months. As the release is nearly completed, the project has cut a release candidate, Scalatra 2.2.0-RC1.

Here’s a quick rundown of what’s changed since 2.1.1, the current stable release. Some new (but incomplete) documentation for this release candidate is also available, at http://scalatra.org/guides/2.2/

Testing, bug reports, and feedback are all very welcome.

Global

  • Removes jerkson support
  • Removes anti-xml support
  • Adds Jackson support
  • Adds common traits for pluggable json serialization. These traits allow library writers to write against a generic json interface. The application developer can then mix in a specific json implementation, such as lift-json or jackson, and retain all functionality
  • Defers reading request parameters until the last responsible moment (aka lazify)
  • Contrib project has been removed. All the contrib modules have been moved into the main Scalatra project

Core

  • Adds typed param support, previously in contrib
  • ApiFormats now also has a method responseFormat which looks at the content type of the response and falls back to the format of the request.
  • The default bootstrap file is renamed from Scalatra to ScalatraBootstrap
  • FileUpload can now be configured through init parameters
  • RouteMatchers don’t use any by-name params anymore
  • RouteMatcher now takes a requestPath as a param to the apply method
  • You are able to mount the same servlet more than once in the ScalatraBootstrap class
  • Added a new relativeUrl method which will compose a path for redirection and keep relative paths relative
  • Refactored the url method to allow for a more granular building of the path with regards to the context path and servlet path
  • Added a fullUrl method which will use the absolute path created by the url method to build a url with protocol, host, port and path + querystring
  • Added a isHttps method which also looks in the headers for a X-Forwarded-Proto header
  • Added a needsHttps method which looks in the init params for a key org.scalatra.ForceHttps for a boolean value (true/false), this is used by the fullUrl method to work out the protocol
  • Added a org.scalatra.HostName init parameter in which you can override the host name of this scalatra application, if unset the value from request.getServerName will be used
  • Added a org.scalatra.Port init parameter in which you can override the port of this scalatra application, if unset the value from request.getServerPort will be used
  • ApiFormats now also has a reverse mapping for the txt extension

lift-json

  • removed in favour of json4s support

Jackson

  • removed in favour of json4s support

JSON

  • previous lift-json support is replaced with json4s support.
  • Jackson integration is also provided through json4s
  • Replaces ProductToJsonSupport trait with a JValueResult trait which will try to serialize any value to json or xml when the accept headers or format parameter indicate the user wants json or xml.

Scalate

  • Adds ScalateRenderSupport trait taken from contrib

Databinding

  • Adds a databinding module for commands. The commands can have validations attached and will read data from headers, params and the request body (like json/xml) This is implemented using an infrastructure of type classes and uses scalaz validations to capture the validation information.
        class RegisterForm extends JacksonCommand { // you have to pick the json library of choice

          val login: Field[String] = asString("login").required.notBlank.minLength(6).validForFormat("\\w+".r)

          val name: Field[String] = asString("name")

          val email: Field[String] = asString("email").required.notBlank.validEmail

          val homepage: Field[String] = asString("homepage").validUrl

          val passwordConfirmation: FieldBinding = asString("passwordConfirmation").required.notBlank

          val password: FieldBinding = asString("password").required.notBlank.validConfirmation("passwordConfirmation", passwordConfirmation.value)

        }

Atmosphere

  • Adds an atmosphere integration. This module adds support for websockets, long-polling, and server-side events.

        class MyAtmoServlet {
          def receive = {
            case Connected =>
            case Disconnected(disconnector, Some(error)) =>
            case Error(Some(error)) =>
            case TextMessage(text) => send("ECHO: " + text)
            case JsonMessage(json) => broadcast(json)
          }
        }

Swagger

  • Added serialization for AllowableValues in Swagger.scala. These are passed as strings in the AllowableValues object:
  // as List
  allowableValues = AllowableValues(1, 2, 3)

  // as range
  allowableValues = AllowableValues(0 to 1000)
  • Updated to support the swagger-1.1 spec
  • Allows for using either jackson or native json to generate the service description json
  • Auto-registers servlets and filters that extend the SwaggerSupport trait in the swagger manager.
  • Includes the swagger-core and swagger-annotations jars as transitive dependencies (batteries included)
  • the models property in the SwaggerSupport can now be Set as Map(classOf[Pet])
  • responseClass can now be set with a type parameter responseClass[Pet]
  • data types in Parameter and ModelField definitions can now be defined as DataType[List[String]]

Swagger-Ext

  • Adds support for authorization through scentry to Swagger. Shows only actions a user is allowed to see. Example
  • Adds support for using commands with Swagger. This creates a model definition for the body parameters and parameter definitions for the query, path and header params as well as a parameter for the body model
  // So your route looks like this:
  get("/id", endpoint("id"), nickname("getById"), parameters[MyCommand])

  // MyCommand is a databinder which takes care of automatic
  // validation and binding of incoming params, and also allows
  // Swagger params annotations to be automatically inferred from
  // the MyCommand params.  
  class MyCommand extends JsonCommand {
    protected implicit val jsonFormats: Formats = DefaultFormats

    val name: Field[String] = asString("name").notBlank

    val age: Field[Int] = "age"

    val token: Field[String] = (
        asString("API-TOKEN").notBlank
          sourcedFrom ValueSource.Header
          description "The API token for this request"
          notes "Invalid data kills cute innocent kittens"
          allowableValues "123")

    val skip: Field[Int] = asInt("skip").sourcedFrom(ValueSource.Query).description("The offset for this collection index")

    val limit: Field[Int] = asType[Int]("limit").sourcedFrom(ValueSource.Query).withDefaultValue(20).description("the max number of items to return")
  }

Testing

  • Added a method ensureSessionIsSerializable method which will try to serialize every session value.

Auth

  • Scentry is now lazily initialized so the order of the traits doesn’t matter anymore