Like many other web frameworks, Bowler needs to do two key things that this post will discuss:
- Map/transform incoming requests into API user defined strongly typed model objects.
- Render an API users View Model as a View of some description (HTML, JSON, XML etc)
This post will detail how Bowler does these two things, and how it can be easily extended and customized, should a Bowler user want to.
Transforming Incoming Requests into User Defined Objects
One of the core objects in Bowler is the singleton object BowlerConfigurator - as the name implies, it is sort of a central point for runtime configuration data in Bowler, relevant to this post it holds information on what RequestMappingStrategy to use, and what RenderStrategy to use.
When a User either uses the ParameterMapper-trait to map explicitly from a Request to his own defined model object, or if he uses the FunctionConventionRoutes-trait (new in 0.4) that allows controllers to define routes-by-function-name-convention and “auto-magically” does the parameter mapping, the following invocation steps will typically happen:
- The ParameterMapper asks the BowlerConfigurator for a RequestMapper implementation.
- The BowlerConfigurator will use its set RequestMappingStrategy, the RequestMappingStrategy will resolve a RequestMapper based on the current Request.
- The ParameterMapper will use the RequestMapper for-each strongly typed parameter it needs to map/translate from the Request. The RequestMapper will return a user defined object instance, IF it can translate the Request properly.
Unsurprisingly, by Default, the DefaultRequestMappingStrategy is used, which looks at the incoming HTTP Content-Type header to decide which RequestMapper to use, for instance the JsonRequestMapper for POSTS/PUT’s with a Content-Type of “application/json”. The DefaultRequestMapper on the other hand will deal with most regular request cases such as path parameters, GET parameters and regular form encoded POST’s.
If an API user wants to add other types of RequestMappers, such as one to deal with application/xml input, it should be relatively straightforward for a user to implement an ApplicationXmlRequestMapper and configure this into the DefaultRequestMappingStrategy in his application Bootstrap class.
If an API user wants to change the RequestMappingStrategy entirely, for instance not use Content-Type as the basis for chosing a RequestMapper, implementing a new RequestMappingStrategy and setting it on the BowlerConfigurator during bootstrap should be equally trivial.
Rendering a View with a Model
The rendering side of Bowler follows a very similar pattern, whereby the trait Renderable is a focal-point: Renderable is a “part-implementation” trait which can be mixed into a Controller, or any other sort of class that may be responsible for rendering.
When Renderable’s “render” function is called with one or several view model objects, it goes through roughly the following process:
- Renderable looks up a RenderStrategy from the BowlerConfigurator.
- The RenderStrategy is responsible for resolving a ViewRenderer given a Request.
- The Renderable then uses the resolved ViewRenderer to render the View with the given view model.
By default, Bowler comes with two RenderStrategies:
- DefaultRenderStrategy: this is the default strategy used unless set otherwise. It follows HTTP “pseudo-strictly”: it does it’s best to follow HTTP, but has some workarounds to deal with bad browser implementations, such as Chrome’s and IE’s poor use of HTTP Accept headers. By default the DefaultRenderStrategy will use the HTTP Accept header, such as “application/json” to resolve a ViewRendererer.
- StrictRenderStrategy: This is a new strategy for 0.4 that will follow the HTTP spec more strictly, including taking relative weighing scores provided by clients into regard. Not appropriate for use for browser based apps, but appropriate if you want client apps to strictly follow HTTP.
If you want to deviate from any of the default RenderStrategies, again, rolling your own implementation and setting it in the BowlerConfigurator during bootstrap is quite trivial.
When it comes to ViewRenderers, Bowler comes with two out of the box:
- ScalateViewRenderer: as the name implies, will render Scalate templates with a given view model. Supports all of Scalate’s templating styles, including Mustache, SSP, Scaml, Jade and Scuery. Probably what you’d want to use for serverside rendering of HTML/XHTML.
- JsonViewRenderer: takes your model and renders, well, JSON from it based on the structure of your view model objects.
Again, adding your own ViewRenderer, such as an ApplicationXmlViewRenderer should be trivial, as should creating a RenderStrategy that uses it be.
Sensible Defaults, Infinitely Customizable
Hopefully this post will give anyone looking to use Bowler an idea on how they can customize request mapping- and rendering behavior. The defaults should be sensible for 95% of cases, as they closely follow the intent of the HTTP spec (although deviates slightly in cases where mainstream browsers force deviation) while being straightforward. But if you want to change behavior, add ways of rendering or mapping, you can have full control with a few lines of extra implementation code.