In Praxis, controllers behave much the same as they do in other MVC-based web frameworks — they expose actions which receive requests from API consumers, operate on resources to service those requests, and return the appropriate responses. In short, controllers are the glue which connects actions and their responses to application business logic.
Praxis controllers differ from some other frameworks in that they:
- are plain Ruby classes that happen to include the
- execute an action by calling a method. Action methods accept Ruby named parameters corresponding to the attribute names of the resource definition.
By using plain Ruby classes, Praxis allows you to use the full power of Ruby. You are not limited in your inheritance options, and your controller code can be well-isolated and easily tested.
Implementing a Controller
To implement a controller in Praxis, include the
Praxis::Controller module in
your controller class and indicate which of your Resource Definitions it
implements by using the
Praxis::Controller module enhances the class with methods such
implements method is used to connect a controller with its
ResourceDefinition. Technically speaking there is nothing that prevents the
same class from being both a Resource Definition and its Controller,
implementing itself. Despite that being feasible due to the modularity that
Praxis provides, we discourage it in order to keep “definitions” logically
separate from “runtime code”.
Once set, you can retrieve the
ResourceDefinition for a controller with the
definition method, which is defined on both the class and instance.
Implementing an Action
A controller action is an instance method defined on a controller class. The method’s name must match an action defined in the controller’s resource definition.
For example, this resource definition class for
Posts defines two actions
The controller implementing this resource definition must have instance methods
show which accept the argument names described by the
params block from the resource definition.
Note that the
index action has no parameters defined in its resource
definition so the method accepts no arguments.
On the other hand, the
show action has four parameters defined in its
resource definition, so it can explicitly declare them as named method
arguments. Ruby gives you great flexibility in declaring named parameters with
the splat operator. It is up to the developer to choose how many explicit
arguments to list, and how many to tuck away inside an
other_params hash. In
this case, the developer decided that
token are important enough to
use as direct variables in the controller, while pushing the
extended_info into the other_params hash. Having this flexibility is
great for dealing with large number of parameters while keeping your controller
In addition to using named arguments for incoming parameters, Praxis will also
ensure their values match the types that you’ve specified in the Resource
Definition. Accessing the
id variable within the
show method will always
get you an Integer.
Retrieving Headers and Payload Data
Praxis::Controller module provides a
request accessor which can be used
to retrieve the incoming
headers and the
payload data. The information under
these methods is type-curated much like parameter definitions. They are
accessible through methods matching your attribute names, and they will always
return values matching the type of your attribute (possibly coercing them if
You can also test if a value exists (or has been assigned by a
default option) for an attribute with the
key? method. This is useful in those cases where there is an important distinction between a user-provided
nil value and the user simply not providing a value, as there is in “PATCH” requests.
For completeness, the request object also gives you access to your
the same way, even though you already get them passed in as named arguments.
Here’s an example of how to access these methods from a controller action:
Returning a Response
Every controller action is responsible for returning a Response object (an instance of a Praxis::Response-derived class) with the right headers, status code and body. Praxis handles the work of delivering your responses to clients.
Instead of having to create a Response object every time, each controller instance comes with a pre-set response accessor containing an instance of the Default response which is 200 OK unless you modify it. Your controller may use and modify the default response or substitute it with another. Or it could ignore the default accessor and return its own Response objects. Here’s an example of one way to use the default accessor:
There is another way to use the default response. If your action returns a string, Praxis will call response.body for you and implicitly use that response.
Request Life Cycle Callbacks
Praxis provides a way to register one or more callbacks before or after named
stages in the request life cycle. This is done using the
methods which take zero or more params and a block for Praxis to execute.
To execute a callback before the
show action runs, you could add:
To execute a callback before the
validate stage of the request cycle, but
only when the action is
index, you could add:
The block receives the instance of your controller, which you can use to access all of the controller’s properties, including the request, the response, any actions, etc.
For a complete discussion of what stages are available for use in your callbacks, as well as how to use them, please refer to the Request Life Cycle documentation.