Under the Hood
OX::Application
Although OX provides a useful sugar layer for writing your applications, it is really just a thin layer on top of an extensible internal structure. Much like Moose and Bread::Board, learning how the internals work can open up a lot more power to your applications.
Bread::Board::Container
An OX application is, fittingly, an instance of OX::Application. OX::Application is just a Bread::Board container class with a service named App
, representing the final PSGI application coderef (in fact, $app->to_app
is just a wrapper around $app->resolve(service => 'App')
). This means that you can do anything with your OX applications that you would with any other Bread::Board container, such as include them in other Bread::Board containers, if your app is larger than just a web application.
The App
service is a block injection service, whose body just calls the build_app
method on the application object itself. This means that defining your application is as simple as writing a build_app
method. The App
service also gets its dependencies via the app_dependencies
method. The service itself, in Bread::Board syntax, basically looks like this:
1: | service App => ( |
As you can see, this supports declaring middleware via an additional Middleware
service. This service is expected to create an arrayref of middleware, and is created similarly to the App
service, via build_middleware
and middleware_dependencies
methods.
Features added by the OX sugar
In addition, the OX sugar provides a default implementation of build_app
that uses an additional Router
service. The Router
service again is created via methods on the application class, via build_router
and router_dependencies
. Since the router is an object, creating the object itself is usually always done the same way, the only difference being the routes that are added to it. To make this process easier, the Router
service is created slightly differently - build_router
has a default implementation that constructs a router object using the router_class
method and the dependencies specified in router_dependencies
, and then it calls configure_router
, passing the constructed router object in.
The default build_app
implementation then calls the app_from_router
method to turn the router object into a PSGI application. It also replaces the app with a Plack::App::URLMap which has the initial app mounted at '/'
if any mounts were declared.
Roles as plugins
The upshot to this is, OX has no explicit plugin interface. Most plugin-like behavior can already be provided via middleware (as we've already seen), and anything that can't be done that way can instead be done by just writing normal roles to be applied to the application class.
For instance, if you (for some reason) want to interpret your requests and responses as Windows-1252 instead of UTF-8, you can do this:
1: | package MyApp::Request; |
Here, we override the request class for the application to use our custom request class, which has a different value for default_encoding
. Any of the other methods mentioned in this article can also be overridden in similar ways. See the documentation for OX::Application for more details, as well as OX::Application::Role::Router and OX::Application::Role::Request which are applied to your class by default when you use OX
.