First Look: Scala Play Framework

Play Framework makes it easy to build web applications with Java & Scala.

Play is based on a lightweight, stateless, web-friendly architecture.

Built on Akka, Play provides predictable and minimal resource consumption (CPU, memory, threads) for highly-scalable applications.

Play was the first framework I picked up in preparation for a talk Kingsley and I gave at Scala Exchange 2016; Scala Services in Action. As it is one I have used before at a previous company, I was keen to go back and see if I still enjoyed using it a year or so later. I was left with a great first impression from using it in industry, which thankfully has held true throughout my experience at home. As part of the talk preparation, I wrote a small REST application that can be found here, where all of the below examples can be found.

+ Documentation

Play’s website was very nice to use, clear to navigate around and included plenty of sample projects to look at. This is all so very useful when looking at a framework for the first time and can’t be underestimated. Everything I needed when writing my example project was easy to find in the Scala documentation and it covered everything in a way that I understood (not as common as you’d think!).

+ Routes

I really liked Play routes. It felt like a natural separation to keep the routes in a configuration file away from the rest of the Scala code. You simply define the route and direct it to a method in the controller, no fussing with syntax or boilerplate. Once you start to accept payloads or query parameters there is a small amount of googling to find out the exact syntax and how to pass them into your method, but nothing too scary or time-consuming.

playroutes2

– Guice

Play comes pre-packaged with a dependency injection framework by Google called Guice. I can’t say I’m a fan of Guice, I particularly found it to be a huge barrier when using Play as a beginner. It’s quite “magic” in the way that it does a lot of things you can’t see and, everyone knows, when magic goes wrong it’s even harder to understand and fix.

Also, as Scala developers we have come to depend on the compiler, and in most cases if it compiles, we already have a decent amount of faith it will work. Guice introduces these runtime errors into your code which is a HUGE downfall. These errors are often misleading or confusing when the project becomes more complex.

playguiceerror

Furthermore, Guice seems to make testing quite difficult to get going with. Granted, I didn’t spend that much time battling with it, I’d already lost my temper with Guice a long time ago so my patience was wearing thin. I just found the effort in understanding what I had to do and what was going on completely unnecessary. Even though I would use Play in the future, I would not use it with Guice.

+ User Interface

Play comes with a user interface without any extra effort required. At first it may not seem like a big deal, especially if you are planning to return json objects. However, the UI helped me quite a bit when I was testing endpoints or getting runtime errors cough *Guice* cough. As shown below, if you get the endpoint wrong, it shows you all the endpoints that are available to you (thumbs up from a lazy developer).

playui

+ Json formatters

On Play’s website it claims they aim to make Json a first class citizen. So, the good news is Play was the only framework where I successfully manipulated the json I was sending or receiving in one sitting. I was able to negate the need for certain unnecessary fields in the json to maximise usability. For example, I nested my case classes, even for those values that only needed one field like this:

playnamecaseclass

This meant by using the default Play json formatters, I would need to be writing json with extra “value” fields like below. sad face.

jsonwithvalue

Another example would be that you would ideally want to model your data with one case class, for example a pet:

petcaseclasswithoutoption

This means this case class will model what your json will look like in the request and the response. However, it may be misleading or confusing to ask for an ID (also shown in the above json) when someone is ‘registering’ a pet, yet our service needs to respond with an ID when the user ‘GETs’ a Pet so they can use it later to update or delete.

Thankfully, Play json custom formatters (and Options) gives you a huge amount of flexibility.

Here is my custom formatter for the above examples:

petplayjsonformatters

– Compilation: When and How long

Play, by default, has “just in time” compilation. I realise this doesn’t sound like a huge problem, and I would agree, but it did get a bit annoying when doing what should be very quick manual tests on the endpoints. Not only do you have to send the request and wait, you have a to wait quite a while – Play does seem to be very slow 🙁 This also means that you don’t get your compilation errors until after you’ve sent a request for the first time:

routesruntimeerrorplay

which is almost as bad as runtime.

+ Cycle time

I realise that speed and usability are factors that are largely subjective and are not a clear reflection of the framework alone. However, I can claim that compared to the other frameworks I’ve had a ‘first look’ at, this tops my list in this category. The documentation is extensive and clear to navigate around, there are many templates available and every question I asked Google was answered dozens of times.

As for going from zero to service; along with the routes I have shown above, all you need is to add this to your build.sbt:

playbuildsbtand add your method straight to a class that extends Controller:

playcontroller

That’s it. No nasty boilerplate and nothing that isn’t directly focused on the service you want to build.

Conclusion

Play came out top favourite in a poll we ran during our talk in the Scala Exchange! I think this is mostly down to the excellent support and documentation you get if you choose Play, you never feel like you’re the only one who’s approached a particular problem. I saw the biggest downfall was the way it introduces runtime errors to a language that loves to depend on the compiler – I would definitely get rid of Guice.

Resources

  • I found a book by Underscore incredibly useful that can be found here. Great for beginners!
  • Activator is an excellent tool for developers to get started with SO MANY tutorials.
  • This blog by Krzystof Pado is great at looking at all of the dependency injection techniques you can use with Play – excellent read if you are looking for an alternative to Guice.

Sofia x

You may also like

8 Comments

  1. Hi. Thanks for the writeup. I very much enjoyed the talk that you and Kingsley gave at Scala eXchange.

    I wanted to point you in the direction of a small library I built that would address the issue you talk about with value classes and json. You can find it here https://github.com/WellFactored/play-bindings

    It uses a little bit of Shapeless to construct Play Json Reads and Writes instances for single-value case classes and does the work of wrapping and unwrapping the contained value to avoid the extra level of nesting in the generated json.

    The library also lets you generate Bindable instances for query and path parameters so you can use string ID types, for instance, in your routes file. The README should explain how to make use of it, but I’d appreciate any feedback on how I could improve it.

  2. Regarding the use of guice, like you when I first moved from play 2.4 to 2.5 and started to have to use dependency injection I was pretty wary of guice, particularly having had bad experiences of it in the past. I’m still not a great fan, but I have to say that it’s not as bad as it first seems. You can get away with a very small amount of it. One specific recommendation I’d make is to not use a centralised modules definition. Instead, you can annotate your traits with @`ImpelementedBy` to provide the default implementation and the extra `@Inject()` on the implementation classes is a relatively minor bit of boilerplate.

    The most annoying thing is, as you point out, the runtime binding that means you can’t get the compiler to tell you if you’ve forgotten to wire things up. The only saving grace there is that Play does early binding of the guice dependencies so at least you find out about the problems when the server is started rather than after it’s been running for a while.

    This was a big change between 2.4 and 2.5 and I know that Kingsley is seeing the major disruption that migration causes, but there was good reason for it. Prior to 2.5 the components of a play app relied heavily on binding to certain global objects in the framework itself, which meant that tests for a lot of bits of the system needed to fire up an entire mock Play Application instance when that shouldn’t really have been necessary. The shift to injection in 2.5 means that this is no longer the case and makes things a lot more easily testable. I just wish they’d found a less-annoying approach to it 🙂

    Maybe you’ve seen this recent blog post that discusses different approaches? http://www.schibsted.pl/blog/dependency-injection-play-framework-scala/

    BTW, if you’d like to see a more in-depth example of a Play application then you could have a look at https://github.com/UKGovernmentBEIS/rifs-frontend-play and https://github.com/UKGovernmentBEIS/rifs-business which are two components of an application I’ve been working on recently that demonstrate everything you talk about in your post but are hopefully still small enough to be approachable.

    Oh, and one final note: In the presentation Kingsley made a comment about the Routes file not being type safe. In fact, Play translates the routes file into a Scala object and it is compiled as part of the build pipeline so they are, in fact, completely type safe.

    1. And thanks from me too Doug! Always super useful and generous with your feedback too!
      And yep, badly phrased wrt Routes file and compilation at ScalaX, totally my bad. Afaik, the file is JIT compiled, meaning the errors are compilation ones, but exposed at runtime on first access. No idea if there’s a way to force eager compilation of the routes ?
      Yup, Shibsted post is in the resources section of the main post by Sofia. It’s awesomes!
      Thanks again Doug! Very much appreciated!

      1. Under the hood Play is just a plugin for sbt so you can always just do a `compile` from the sbt prompt and that will include compiling twirl templates and the routes. Maybe all this gets a bit hidden from you if you’re using activator,

        I haven’t had a chance to really try out any of the other approaches to DI yet. So far guice has been “good enough” and not quite annoying enough to spend time on investigations, but I always come away from using guice feeling slightly grubby:-)

          1. Yeah, I saw Eric Torreborre talk about Grafter as part of his Eff talk at ScalaX. Interesting approach.

Leave a Reply

Your email address will not be published. Required fields are marked *