So you’re new to Praxis, you’ve read some of the cool stuff that it can do and you’re ready to give it a try.
Great! Let’s get started by creating an API resource from scratch with documentation, and querying our running API server from the command line. We’ll be making a simple Post resource for a blog application, but before we do that, we need to set up our app.
Setting Up a Praxis App
Once Praxis is installed, the easiest way to get up and running is to use the Praxis app generator to create a sample app. In order to use the app generator, you’ll need to install the Praxis gem.
bundle install to install the app’s gem dependencies:
You already have a basic Praxis application, that includes a sample resource called hello! Now you can look at the routes it exposes:
Use rackup to start the app:
Now you can hit one of the app’s routes to see it working:
Congratulations, you’ve just received a response from your first Praxis app! Try these other commands, and see what you get:
Once you’ve finished testing the
Hello controller, type
CTRL+c in the
terminal where you started the server earlier to kill your Praxis app.
Now it’s time to get your hands dirty and see how to use Praxis to build services with full-featured REST APIs.
Praxis uses the randexp library to generate examples given regular expressions, which expects to find a word list (dictionary) in one of three common locations:
This should be present by default in OS X as well as most (but not all) Linux distributions. If you receive an error like “Words file not found. Check if it is installed…” then you need to install a package that provides one.
For yum-based distributions, you need the the
Design vs Implementation
One of the goals of the Praxis framework is to allow designers to define a complete API specification without writing a single line of business logic. When creating a Praxis application, design and implementation should be treated as separate, independent phases.
The output of the design phase is a full specification of the API. This includes API versions, resources, actions, routes, parameter validation, and definitions of the media types returned by every action. You can view a human-readable version of the API specification using the API browser included with Praxis, but the specification is also available in JSON format.
Praxis differentiates itself from other frameworks in that everything defined in the design phase is actual code that will be enforced when the app runs. In other words, the API specification is intimately tied to its implementation. Praxis guarantees that link is never broken, so the documentation is always correct with respect to API behavior. A forgetful developer or documenter cannot cause the documentation to become stale.
The second phase of building an API consists of actually implementing the business logic behind each of the controller actions. However, this excludes all the boilerplate code for validating and coercing incoming parameters because the framework takes care of that based on the specification you’ve already defined in the specification.
To build a Praxis app, start by designing the API. This example API will expose
Post resource and two simple actions:
Creating a ResourceDefinition
To expose an API resource in Praxis, create its resource definition which is
just a Ruby class that includes
version method to define which API version this resource supports.
create actions by calling the
Note: We wrapped the
Posts class here in the
modules to better organize our code. This also allows us to create other
versions of the Posts resource later.
Now you have two actions defined, but Praxis needs you to fill in the interface specification before you can use them. Take the following example:
In the :show action definition, use the
routing DSL block to specify that
you want to respond to the
GET HTTP method for requests to the
URL path. For example, requests such as
GET /posts/1 will be routed to
show action. Furthermore, the
:id attribute in the URL is
Integer and is marked as required. The action also accepts an
:allow_deleted parameter, which could allow clients to indicate that
they wish to retrieve posts even if they have been deleted. By making
Attributor::Boolean and setting its default value
false, you can avoid worrying about these details during
implementation and improve the clarity of the generated documentation.
routing DSL block again to mount the
create action to the
POST HTTP verb
/ path. This action has no required or optional URL
parameters, but it does accept a payload with a required
and an optional
content attribute. Both attributes are of type
Note: You might have noticed that the
show action’s routing block uses
get '/:id' rather than
get '/posts/:id'. Very observant! This is
ResourceDefinition class has a default prefix that applies
to all of its actions. The default prefix for a resource definition is the
snake-cased name of its class (e.g.,
/user_comments). You may specify an
alternative prefix by calling the
prefix method with the prefix you want
to use. See the documentation on Resource Definitions and
Actions for more information.
Check the application’s routing table to make sure the Posts resource appears:
There they are! We can now see a show and a create action for the Posts resource. The observant reader might have also noticed that the implementation column tells you there are currently no implementations of these actions.
Building API documentation
Now you can see that Praxis knows about your Posts resource routes, but how can you start reviewing the interface details for these actions? Ask Praxis to generate documentation for you:
This generates a series of JSON files with the full specification of the API we have defined thus far. This JSON specification is readily consumable by dynamic client generators or converters to other existing formats.
Thankfully, Praxis can generate the same documentation in a more human-friendly format:
which should open up a new browser page for you, pointing to the documentation browser (typically at
http://localhost:9090). This task will automatically detect any changes to your design objects, and redisplay the results the browser for you. It is common to have the browser and the API design editor side by side, to see the changes as new things are added or edited.
If you have the praxis gem installed in the system, you can directly use its executable. In this case, typing
praxis docs would be equivalent to (
bundle exec rake praxis:docs:preview). See
praxis --help (and
rake -T) for more commands and information.
For our example, the doc browser should show you something like this, which incudes the already existing
definition of the sample ‘hello’ app, plus your
Posts resource, including
both actions and their URLs, parameters and payload specifications.
Creating a MediaType
An API specification should define not only what the service accepts, but also what it returns. One way to achieve this is to use application-specific internet media types in responses. And for extra credit we can also define the associated attribute structure of these media types.
In Praxis, media types:
- define their representations by declaring classes that extend
- can be associated with resource definitions as a default internet media type
- document the their representations and their use in resource definitions
So, how does that work for your Posts resource? Very easily.
Start by defining the representation of your
Post media type by creating a
class derived from
Praxis::MediaType. In that class, specify your internet
mediatype name (i.e. ‘application/vnd.acme.post’) using the
method and proceed to define the media type’s attributes.
create action already describes two attributes for a
resource, but you can add more. In this example, you’ll add an
id and an
Once you have all the possible attributes listed, you can define one or more
named views using a
view DSL block. Each view may include a different
subset of attributes to display. Views are very useful when we wish to render
different attributes for different purposes. In this case, create a
default view that contains all the attributes and a
containing only the href of the post:
Save this as design/v1/media_types/post.rb and there you have it! A full Post media type. So now, how do you associate this Post media type with your Posts resource?
To use this newly defined media type, change the
in our Posts resource definition from th 'application/json' string to the full
class. By doing this, Praxis will know that, by default, actions belonging to the
Posts` resource definition are likely to generate responses of this
Resource’s default media types are used when response declarations
that can take a
media_type parameters are left unspecified. For example,
response :ok in the show action is equivalent to
response :ok, media_type: MediaTypes::Post.
Associating a default MediaType to a resource definition has another convenient effect when defining payload attributes. It can help simplify syntax. Here’s how:
It is good practice in RESTful APIs to be able to accept incoming resource
payloads that closely match resource responses receive from the same API. If
you get a result from a
show action, you should be able to easily modify
parts of it, and re-POST it to the API to save some changes. Because of this,
Praxis will assume that any payload definition of any action is closely related
to the default MediaType of the Resource. By doing that, the designer can
define attributes by name, without being required to specify the type and/or
options that might exist in the associated MediaType.
In other words: payloads you define can inherit any attribute definition of the same name that exists in the MediaType associated with the resource definition.
So, by adding the default mediatype in the Posts resource, your
action payload can be simplified from:
Now you have integrated a fully defined MediaType with your resource definition. If you regenerate the documentation and take a peek, you’ll now see its full definition in all its glory.
Please see media types, for more information.
At this point you have designed a
Posts resource with actions. You have
defined their routes, their parameters and an associated MediaType structure
with some renderable views, all without writing a single line of controller or
business logic code. Pretty groovy, huh?
Discussing the API interface at this stage, using the API browser, might save a lot of time and effort before proceeding with the implementation of the actual business logic. But now it’s time for implementation.
Praxis controllers are semantically very similar to any other “C” in most existing MVC frameworks. They implement the business logic for the actions of a resource and renderer a suitable response. Praxis controllers do differ from those of other web frameworks in that Praxis controllers:
- are plain Ruby Objects (easy testing!)
- receive typed and named method parameters in their signature (with the types you have specified in your action definition of your resource)
Creating a controller
To create your Posts controller, start with a Posts class which includes the
Praxis::Controller module. Then use the
implements method to tell
Praxis that this class implements the
Posts resource definition.
Define a method for each your actions, show and create. The method signature
follows the named
params attributes of your actions. The
params and no
create action has a
payload but no
contents are not mapped to the method signature.
Please see controllers, for more information.
Your parameters are name-checked by Ruby at runtime, plus Praxis will make sure their values conform to the type you’ve defined in your resource definition. If there is any error loading or coercing values from the incoming request, Praxis will return an appropriate validation error response telling you exactly what happened. Score!
Response generation is a broad topic, not covered in great detail here. In general, a controller needs to return an instance of Praxis::Response-derived class. There is one exception for strings. If you return a string from a controller, Praxis will create an instance of the action’s default response and fill in the body with the string you returned.
There is much more related to responses that the framework provides, including defining their expectations, specifying which actions can return which resources, and runtime validation that returned responses match the specified expectations.
Please see responses, for more information.
Example generation is another area that requires much more explanation.
However, for the sake of completeness, and because of the suspicious
MediaTypes::Post.example.render(:default) call to generate a hash in the
show action), we should say a few words.
Praxis (in conjunction with its Praxis::Mapper and Attributor gem dependencies) comes equipped with a very powerful way to:
- generate unique (or repeatable) examples of MediaType objects
- render them using any of their defined views
Rendering refers to generating a hash representation of a MediaType’s attributes. That hash can then easily be taken and output to the specific desired format such as a JSON string.
In particular invoking a MediaType’s
.example class method will generate
an instance object with a fully-typed example structure as defined by its
attribute names and types. As a MediaType instance, you can then take that
object as ask it to be rendered according to one of the named views that you
In this case, you have used the
default view, which should produce a hash
with values for
content keys. Being able to
generate examples for all kinds of types makes for nice documentation, but it
also can create real-looking API responses for your tests.
We now have a fully defined, and fully implemented Post API service. We can review its docs, check the routes, start it up, and test that it responds correctly in both success and error scenarios.
Start it up, and check it out!