Rob Kinyon




In your REST API class:

  package My::Sims::REST

  use base 'DBIx::Class::Sims::REST::MySQL';

  sub get_schema_class { return 'My::Schema::Class' }


In a rest.cgi file (somewhere):

  use My::Sims::REST;
  use Web::Simple 'My::Sims::REST';


Then later:

  plackup <path/to/your/rest.cgi> -p <PORT>

And, finally, in your test (or some library your tests use):

  my $data = {
      databases => [
              database => {
                  name => 'database name',
                  username => 'some username',
                  password => 'some password',
              spec => <DBIx::Class::Sims specification>,

  my $ua = LWP::UserAgent->new;
  my $req = HTTP::Request->new(POST => 'http://<URL>:<PORT>/sims');
  my $res = $ua->request($req);

  return decode_json($res->content);


DBIx::Class::Sims provides an easy way to create and populate test data. But, sometimes, your application isn't built on DBIx::Class. Or Perl. These issues shouldn't get in the way of using good tools. (Even if your application or test suite aren't in Perl.)

Assumption: Everything can issue an HTTP request.

Conclusion: The Sims should be available via an HTTP request.


This is a skeleton base class that provides the basic functionality for a REST API around DBIx::Class::Sims. By itself, it only takes the request, parses it out, and invokes a series of methods that have empty implementations. You are supposed to subclass this class and provide the meat of these methods.

You will have to create a DBIx::Class description of your schema (or, at the least, the bits you want to be able to sim in your tests). It really isn't that difficult - there are examples in the test suite for this module.

Once you have all of that, you will need to host this REST API somewhere. Since its purpose is to aid in testing, a good place for it is in your developers' Vagrant VMs, and also in the VM you use to run CI tests on.

THIS SHOULD NEVER BE MADE AVAILABLE IN PRODUCTION. If you do so, the problems you will have are on your head and your head alone. I explicitly and categorically disavow any and all responsibility for your idiocy if this ends up in your production environment. Please, do not be stupid.


The full data structure to be passed via a request is as follows:

      defaults => {
          database => {
              username => '',
              password => '',
              root => {
                  username => '',
                  password => '',
          create => 1,
          deploy => 1,
      databases => [
              database => {
                  username => 'username',
                  password => 'password',
                  name     => 'name',
                  root     => {
                      username => 'root_username',
                      password => 'root_password',
              create  => <0|1>,
              deploy  => <0|1>,
              spec    => < First parameter to load_sims() >
              options => < Second parameter to load_sims() >
  • databases

    Each entry in this array represents the setting up of a single database. You may want to set up multiple databases at the same time, hence the ability to specify multiple databases. Each entry will be executed in the order they are specified, if that matters. Each entry can decide whether or not to create or deploy, as appropriate to your purpose.

    • create

      This will drop and recreate the database. This defaults to true. If this is set, then deploy will also be set.

      This requires the root username, password, and whatever create commands are required to be set. Please see the appropriate sections of the documentation for further information.

    • deploy

      This will deploy the schema per <$schema-deploy(add_drop_tables => 1)>>.

    • spec

      This is the meat and potatoes of this module - the reason why you're here.

      Please see "load_sims" in DBIx::Class::Sims for further information.

    • options

      "load_sims" in DBIx::Class::Sims has an optional second parameter of options. This allows you to set them. Please see that documentation for further information.


If all goes well, the response will be an array of the return values from "load_sims" in DBIx::Class::Sims. The array will be in the same order as the databases element of the request.

If nothing happens, the response will be exactly:

  { "error": "No actions taken" }


You have to override the following methods for anything to work.

get_schema_class( $item, $defaults )

This method should return a string containing the package name for the schema. It can use anything in the entry and the defaults.

If it returns nothing, then this entry will be skipped.

You MUST provide an implementation of this method - the base implementation throws an error.

get_connect_string( $item, $defaults )

This method should return the first parameter in the connect() method. It can use anything in the entry and the defaults.

If it returns nothing, then this entry will be skipped.

This method has implementations in the SQLite and MySQL subclasses. Otherwise, you MUST provide an implementation of this method - the base implementation throws an error.


get_username( $item, $defaults )

This method should return a string to be used as the username in the connect string.

The base implementation returns the username from either the $item or the $defaults.

get_password( $item, $defaults )

This method should return a string to be used as the password in the connect string.

The base implementation returns the password from either the $item or the $defaults.

get_root_connection( $item, $defaults )

This method should return a DBI $dbh that has a root connection to the database. This is what the return value of get_create_commands() will be passed to.

The base implementation retrieves the root username and password from the database entry in the $item or $defaults, then uses the value from get_connect_string() to connect to the database. This should be sufficient for most purposes.

get_create_commands( $item, $defaults )

This method should return an array of SQL commands to be executed via a root connection when a database is dropped and created. These commands will be executed when <create = 1>>.

The base implementation returns an empty array.

populate_default_data( $schema, $item, $defaults )

This method is called after create/deploy is processed, but before <$schema-load_sims()>> is invoked. You can use this method to do any default data population. For example, to invoke DBIx::Class::Fixtures or to call "populate" in DBIx::Class::Schema.


Additional Keys

The keys listed thus far in $item are only those DBIx::Class::Sims uses internally. You are more than welcome to add additional keys as you need. Then, in the various methods that are passed $item, you can pull those out.

Multiple databases

Your tests may need multiple databases to be populated. This is why the data specification requires a databases array. The $items will be processed in the order they are specified, in case that matters.

You can combine this with adding an additional key to specify which database this $item is dealing with. That way, you can have a different schema class, different default data, etc.


  • Chef/Puppet recipes for auto-launching the REST API

  • Figure out how to pass the class into plackup without an envvar.


This module is hosted on Github at Pull requests are strongly encouraged.


DBIx::Class::Sims, Web::Simple


Rob Kinyon <>


Copyright (c) 2013 Rob Kinyon. All Rights Reserved. This is free software, you may use it and distribute it under the same terms as Perl itself.