Catalyst::Controller::ElasticSearch - Thin proxy for ElasticSearch with some protection


version 0.1.0


This controller base class provides some basic protection for your ElasticSearch server. This will allow you to publish individual indices and types through your Catalyst application. The controller will prevent malicious requests such as huge size parameters or scripts.

ElasticSearch's _search endpoint is very powerful. And with power comes great responsibility. Instead of providing the vanilla search endpoint, it is recommeded that you predefine searches that process only certain parameters. See "DISABLING FEATURES".

Exposing ElasticSearch to the Internet is dangerous. MetaCPAN is doing it, and this module is the result of what we've learned so far.


 package MyApp::Model::ElasticSearch;
 use Moose;
 use ElasticSearch
 extends 'Catalyst::Model';

 has es => (
    is => "ro",
    default => sub { ElasticSearch->new },

 package MyApp::Controller::Twitter;
 use Moose;
 extends "Catalyst::Controller::ElasticSearch";

    model_class => "ElasticSearch",
    index => "twitter",

 package MyApp::Controller::Twitter::Tweet;
 use Moose;
 extends "MyApp::Controller::Twitter";

    type  => "tweet",

    # defaults
    max_size      => 5000,
    allow_scripts => 0,
    get_raw       => 1,



The name of your model class that connects to ElasticSearch. Basically the name you would use to access it via "model" in Catalyst.

This controller is very flexible and accepts any model class that provides a _es or es method that returns a ElasticSearch instance.

If you want to use ElasticSearchX::Model classes in the controller, provide a esxmodel method in your model that will return an instance of ElasticSearchX::Model.


The ElasticSearch index this controller will handle. "index" and "type" can also be ArrayRefs or _all. See ElasticSearch for more information.


The ElasticSearch type this controller will handle. The type is optional.


Defaults to 5000. A http status 416 is returned in case the user exceed the size limit. The size parameter is evaluated both from the query parameter as well as in the request body.

Setting max_size to 0 will disabled the check.


Disable to only retrieve the _source or fields key if requesting a resource by its ID (i.e. no searching). This might be more convenient because the client doesn't has to traverse to the actual data but it also breaks clients that expect the ElasticSearch format that includes type and index information.


Malicious scripts for scoring can cause the ElasticSearch server to spin or even execute commands on the server. By default, scripts are not enabled.


If you want to disable certain features such as search, get or mapping, feel free to override the corresponding methods.

 sub search {
    my ($self, $c) = @_;
    $c->detach("error", [403, "Disabled _search"]);

 sub by_color : Path  : Args(1) {
    my ($self, $c, $color) = @_;
    my $model = $self->model($c); # does security checks
    eval { $c->stash(
            index => $self->index,
            type => $self->type,
            size => $model->size,
        ) );
    } or do { $c->detach("error", [500, $@]) };


By default, this controller will create the following endpoints for a controller named MyApp::Controller::Tweet.



This will return the ElasticSearch mapping.



Will return the document $id. If "raw_get" is set to false, the returned JSON will not include the ElasticSearch metadata. Instead the _source or fields property is returned.



This endpoint is equivalent to /tweet/_search?q=*.


This endpoint proxies to the search endpoint of ElasticSearch. However, it will sanitize the query first.


As with other controllers, you would do the access control in the auto action.

 sub auto : Private {
    my ($self, $c) = @_;
    return $c->detach("error", [403, "Unauthorized"])
        unless $c->user->is_admin;
    return 1; # return 1 to proceed



 $c->detach("error", [404, "Not found"]);
 $c->detach("error", [$code, $message]);

This helper action can be used to return a error message to the client. The client will receive a JSON response that includes the message and the error code. If the message is a ElasticSearch::Error, the corresponding error message will be retrieved from the object.


Moritz Onken <>


This software is Copyright (c) 2013 by Moritz Onken.

This is free software, licensed under:

  The MIT (X11) License