++ed by:
Author image Anton Petrusevich
and 1 contributors


Dancer2::Plugin::OpenAPIRoutes - automatic routes creation from Swagger specification file.


  use Dancer2;
  use Dancer2::Plugin::OpenAPIRoutes;


Automatically creates Dancer's routes from Swagger specification file. Extracts request parameters according to given spec. Uploaded files are Dancer2::Core::Request::Upload objects.

Automatically decodes JSON parameters if "Content-Type" is application/json. Automatically encodes answers to application/json if "Accept" header asks for it and returned value is reference.

IFF JSV::Compilator module was loaded before, then it will be used for input data validation. Otherwise it checks whether parameter is required or not but doesn't do real validation.

Catches thrown exceptions and makes JSON error messages if "Accept" is application/json.

Makes very smart mapping from route to Module::handler_function. For example:


will be mapped to Order::create(), Order::remove() and Order::update() accordingly.


Schema details will be taken from your Dancer2 application config file, and should be specified as, for example:

      schema: public/swagger.yaml
      namespace: MyApp
      default_module: MyApp

Location of the Swagger spec file relative to the project root.


Starting namespace for generated module name.


Module name to put root's routes.

You have to call OpenAPIRoutes([$debug_flag, $custom_map]) in your main application module. Optionally you can pass true value as first argument to see how it maps routes to Modules and functions.


This is probably the most crucial feature of this plugin. It automatically makes your application structured according to given spec file. It also makes your application less dependent on Dancer2 framework - you have to think more about application logic and less about framework details. Mapping is complicated but intuitive.


Both the route and its HTTP method are used to compose the mapping.


This is starting point of the mapping algorithm. If route has only one method, then route's last part can be used as function name in module which name made of previous route parts.


In RESful terms POST means creation of some resource. That's why usually it maps to create() function with one exception: if route ends with /{someId} then it means update().


This methis is mapped to function fetch().


This method is mapped to remove(). Perl language already has delete() function and it's better not to reuse its name.


In RESful terms PUT means full replacement of some resource. This method is mapped to replace()


In RESful terms PATCH means partial update of some resource. This method is mapped to update()


This method is mapped to choices()

This method is mapped to check()

You don't usually have to define HEAD method because it's done automatically from GET throwing away real answer.


Basic idea is very simple: /resource/subresource is mapped to Resource::Subresource module and function name is mapped according HTTP method. Then there're special cases (from OpenAPI example spec):

POST /pet/{petId}/uploadImage
GET /pet/findByTags
GET /pet/findByStatus

It would be silly to put these three routes with single method in separate modules Pet::UploadImage, Pet::FindByTags and Pet::FindByStatus. That's why routes with only one method are mapped to theirs "parents" with function name from last route part.

NOTICE: It's important to describe path parameters twice: in route and in parameters method's section. Because they are extracted as regexp captures and routes with integer parameters should be dispatched first to avoid collision between /pet/{petId} and /pet/findByTags type of routes.



When you need some variable from PSGI's environment, like REMOTE_USER, then it's really inconvenient to get directly from Dancer2 framework. There's a support to get it automatic using OpenAPI extension keyword x-env-{environment-variable} like x-env-remote-user: user. This keyword should be put in HTTP method section. Directive x-env-remote-user: user will put value of PSGI's environment variable REMOTE_USER into input hash parameter key user.


Mapped route's function is called like this:

  ($result, $status, $callback) = ${module_name}::$module_func( \%input, $dsl );

Function receives hash reference with extracted parameters according to Swagger spec and Dancer2 DSL object. This object is rarely needed but sometimes you need to have access to application's object, for example:


Most of the time function can return only one result like this:

  sub fetch {
    my $input   = $_[0];
    my $pet = schema->get_pet( $input->{petId} );
    return $pet;

Sometimes you want to change response status:

  sub remove {
    my $input = $_[0];
    my $error = schema->delete_pet( $input->{petId} );
    if ($error) {
        return ( { error => $error }, 'bad_request' );
    return ( '', 'no_content' );

In some odd cases when you use old Dancer2, then you have to call specific functions directly from route handler using callback:

  sub downloadFile {
    my $dsl      = $_[1];
    # ... 
    return (
      undef, undef,
      sub {
          filename     => $filename,
          content_type => 


When you need some customization to your routes mapping, you can do it passing hash reference as second parameter to OpenAPIRoutes([$debug, $castom_map]). You can change mapping for HTTP method for all paths or only for specific ones like this:

  OpenAPIRoutes(1, {"get:/store/order/{orderId}" => "remove"});

(Very naughty joke): Instead of calling "fetch" for this specific path it will call "remove". The whole schema:

  OpenAPIRoutes(1, {"$method[:$path]" => "[$function]:[$full::module::name]"});

like this:

  OpenAPIRoutes(1, {
      "put"               => "update",
      "post:/store/order" => "create_order",
      "post:/store/image" => "upload_image",
      # and so on ...


This module was written and is maintained by:

  • Anton Petrusevich