CKAN plugins - IRoutes

This blog post is almost certainly out of date. You should check the CKAN docs - they’re pretty awesome.

Although the CKAN extension documentation is fairly complete I thought it might be useful to document some examples for each of the plugin interfaces that are available to you as a CKAN extension author. They’re not going to be fully complete plugin examples, they already exist, but rather just more basic guidance on what you can do with each plugin and how.

IRoutes

The IRoutes plugin is used to add new URLs to your CKAN instance. Typically you’ll use it when you have created a new Controller, and you want to set up certain URLs to call the actions on that Controller, but it can also be used to add fall-back URLs.

To implement IRoutes, your code will probably look something like this:

import ckan.plugins as p

class MyPlugin(p.SingletonPlugin):
    p.implements(p.IRoutes, inherit=True)

    def before_map(self, map):
        controller = "ckanext.myplugin.controllers:MyController"
        map.connect("something", "/something",
            controller=controller, action="index")
        map.connect("something_view", "/something/{name}",
            controller=controller, action="view")
        return map

    def after_map(self, map):
        return map

As the documentation explains, p.implements(p.IRoutes, inherit=True) is how you tell CKAN that your plugin provides that functionality, in this case adding to the routing table. The part of that call inherit=True simply means that if you do not implement one of the methods of the interface then a default implementation will be provided for you. So, in our code above we could just remove after_map(self, map) if we’re not going to implement it, and it’ll all still work. It’s probably easier to just always have inherit=True.

Using the map

In our before_map call above, we have a line that looks like controller = 'ckanext.myplugin.controllers:MyController', this is using a dotted-module-name to find the module (ckanext.myplugin.controllers in ckanext/myplugin/controller.py) and then the class to load is the name following :. You had to use this format when modifying your setup.py to point to your plugin.

The following two lines are used to specify the new URLs we want to add, and which action to call for each.

map.connect(
    "something",
    "/something",
    controller=controller,
    action="index"
)

This line gives the URL a name (“something”), so that it can be looked up by name, using toolkit.url_for('something').

The next parameter ("/something") is the URL to be mapped. This example is pretty straightforward, but you might want to support /something/here and /something/else, in which case you specify the URL as /something/{name}. The action parameter specifies the name of the method in your controller class. You should remember though, that if you use a named parameter in the map.connect() call that you need to add that parameter to the method signature.

# /something
def index(self):
    pass

# /something/{name}
def view(self, name):
    pass

More information

Under the hood, CKAN uses the routes library v1.13 to handle the route generation, so that should be the next port of call if you need more information on defining more complex routes. In particular: