1

Yesterday I read a tweet disparaging Jersey with JAX-RS due to run-time errors. Spray.io was mentioned in the tweet:

Not even 5 minutes using Jersey / JAX-RS and already a runtime error due to a missing annotation. That's why I like @sprayio: type safety.

https://twitter.com/gbelrose/status/467295643053338626

How does spray.io provide type safety?

Could you please give an example?

4
  • 1
    See “Discuss this ${blog}” on meta for why this question doesn't seem to be a good fit here.
    – amon
    May 17, 2014 at 13:52
  • 2
    With respect to this answer, I'm asking how spray.io provides type safety. I appreciate your insight, and I agree with the question asked in your link. Not being defensive here, but I genuinely want to know how spray.io delivers type safety. Could you please recommend how to re-word this question (or move it)? May 17, 2014 at 13:57
  • 2
  • This tweet that I posted (a while ago) referred to the lack of safety in JAX-RS when marshalling / un-marshalling entities. In my particular case, the code failed at runtime because I had forgotten to register the serialiser class. I felt the Spray code was a bit better because it would not compile if the compiler could not find the correct type class to marshall / unmarshall a certain object.
    – Guillaume
    Feb 1, 2016 at 8:55

1 Answer 1

4

There are several components to the type-safety of spray. Here's a selection

  1. more-or-less complete model for HTTP data structures including many headers
  2. type-class-based (un)marshalling infrastructure
  3. type-safe data extraction in the routes, type-safe combination of route parts

To explain a bit more

  1. A complete model for HTTP means that after parsing (or constructing) an HTTP message follows a certain fixed structure and certain invariants are met. E.g. this means user-level parsing of headers is usually not needed and runtime errors in code dealing with those headers can be ruled out to some degree.

  2. The (un)marshalling infrastructure ensures statically that values of domain types can only then be converted into HTTP data structures if a marshaller for that type is statically available (through implicits). That means that in a route you can usually work on the level of your domain types with all the logic bridging the types being tucked away in Marshaller definitions.

  3. In spray's route structure you can extract values from a request. E.g. you can use parameters('name.as[String], 'age.as[Int]) to access the name and age query parameter of a request. Using as[T] means that the extracted value will be converted into the type T at runtime. Inside the parameters route you know that name and age will be of the right types (otherwise spray will generate an appropriate error message for the client).

    spray's routes are composed of "directives". Each directive has a type Directive[T1 :: T2 :: ... :: HNil] where the T1... are types of values that are extracted by a directive. Directives can be freely composed, that means that instead of parameters('name.as[String], 'age.as[Int]) (which is of type Directive[String :: Int :: HNil]) you could also write parameters('name.as[String]) & parameters('age.as[Int]). This allows you to extract common patterns in your route into your own custom directives that you can re-use anywhere.

    See the spray documentation on directives for more information about this topic.

It would also make sense to talk about points where spray isn't type-safe (some of those points may be addressed in the future, others are inherent in the architecture). E.g.

  • You can miss the ~ operator while building a route.
  • It can be hard to see if a content-type is allowed/generated for a route or not.
  • It is currently possible not to handle a request in the route.
  • A service you "ask" for an answer to a request (see the Akka ask pattern) may answer with an unexpected kind of message.
  • You can violate the message protocol to spray actors (which is common to all message flow with Akka actors which is untyped).
  • ...

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.