Dance with rose in one hand....
I always wanted to write about Perl but never got the time to do. Recently came across to some of Neil Bowers published blogs which gave me the necessary push to write something useful. I feel honored to have worked with Neil Bowers in the past.
For the last 6 years or so I never got the opportunity to do any kind of web development. Although I kept in touch with all the web related stuff that is happening in the Perl e.g. Catalyst, Dancer, Moose. Also during my web development period, I never used any kind of MVC, ORM but these days everyone wants all these. So cut the long story short, I created the web app using the traditional perl-cgi-dbi logic, which as expected they didn't seem to approve it.
This forced me to re-work on the web app using the MVC and ORM just to get a feel of it. As always with perl, you get plenty of choices to pick from, for MVC, I had choices like Catalyst, Dancer. for ORM, I had DBIx::Class, Rose::DB. I started with Catalyst but found it too complex for the simple web app I was working on. So I picked up Dancer which seems to have very good documentation. I simply followed the documentation and built the web app (RESTFul) in no time. For ORM, I started with DBIx::Class but then had to use Rose::DB for its simplicity. Just to clarify one point here, I am not in anyway suggesting one is better than the other. Its just my personal preference to pick Dancer with Rose::DB for its simplicity. I knew that I am not building full fledged web app, its a very simple web app to list items, search an item, update item tag and ability to upload items.
Here is how the code is structured in the tar ball.
│ Build.PL │ Changes │ config.yml │ Makefile.PL │ MANIFEST │ MANIFEST.SKIP │ META.yml │ README │ setup.sql │ SIGNATURE │ ├───bin │ server.pl │ ├───environments │ development.yml │ production.yml │ ├───lib │ │ WebApp.pm │ │ │ └───WebApp │ │ DB.pm │ │ Helper.pm │ │ │ ├───DB │ │ Object.pm │ │ │ └───Model │ │ Category.pm │ │ Item.pm │ │ │ ├───Category │ │ Manager.pm │ │ │ └───Item │ Manager.pm │ ├───public │ │ 404.html │ │ 500.html │ │ dispatch.cgi │ │ dispatch.fcgi │ │ favicon.ico │ │ │ ├───css │ │ error.css │ │ style.css │ │ │ ├───images │ │ perldancer-bg.jpg │ │ perldancer.jpg │ │ │ └───javascripts │ jquery.js │ ├───t │ 001_base.t │ 002_index_route.t │ └───views │ display.tt │ index.tt │ search.tt │ tag.tt │ upload.tt │ └───layouts main.tt
Lets start building the database using the setup.sql, I am using sqlite3 here, to keep it simple.
> sqlite3 WebApp.db < setup.sql
This should create two tables 'categories' and 'items' with some data.
So now we have a database ready, lets build the backbone of ORM using Rose::DB, we call it WebApp::DB who inherits from Rose::DB. This is a very tiny module which register the database we are going to use like below:
__PACKAGE__->use_private_registry; __PACKAGE__->register_db( driver => 'sqlite', database => 'WebApp.db' );
Now we are going to create a module that provides the database handler, we call it WebApp::DB::Object who inherits from Rose::DB::Object. In this module we defined a method called init_db() something like below:
sub init_db { WebApp::DB->new }
Lets create model for the table categories, we call it, WebApp::Model::Category, who inherits from WebApp::DB::Object to get the database handler. In this module we setup the table structure like below:
__PACKAGE__->meta->setup ( table => 'categories', columns => [ id => { type => 'int', primary_key => 1, not_null => 1 }, name => { type => 'varchar', length => 255, not_null => 1 }, ], unique_key => 'name', );
Similarly we will do it for items table and we call it, WebApp::Model::Item who also inherits from WebApp::DB::Object.
__PACKAGE__->meta->setup ( table => 'items', columns => [ id => { type => 'integer', not_null => 1, primary_key => 1 }, name => { type => 'varchar', length => 255, not_null => 1 }, category_id => { type => 'integer' }, tag => { type => 'varchar', length => 255 }, ], foreign_keys => [ category => { class => 'WebApp::Model::Category', key_columns => { category_id => 'id' }, rel_type => 'many to one', }, ], );
You will notice we added the foreign_keys definition and linked it to categories table. To help us deal with multiple rows, we are now going to create manager for each of the table inheriting Rose::DB::Object::Manager. For categories table, we call it WebApp::Model::Category::Manager. In this module we define a method object_class().
sub object_class { 'WebApp::Model::Category' } __PACKAGE__->make_manager_methods('categories');
Lets do the same for the items table, we call it, WebApp::Model::Item::Manager.
sub object_class { 'WebApp::Model::Item' } __PACKAGE__->make_manager_methods('items');
Now we have the done the ORM bit required for this web app. Lets focus now on Dancer to build the front-end. We need to setup the environment one for development and another for production. Here is how it looks like:
production.yml# only log warning and error messsages log: "warning" # log message to a file in logs/ logger: "file" # don't consider warnings critical warnings: 0 # hide errors show_errors: 0 # cache route resolution for maximum performance route_cache: 1development.yml
logger: "console" # the log level for this environement log: "core" # should Dancer consider warnings as critical errors? warnings: 1 # should Dancer show a stacktrace when an error is caught? show_errors: 1 auto_reload: 0
Lets create the layout for the web app, we call it, main.tt. and one for each task i.e display.tt, search.tt, tag.tt, upload.tt and index.tt
Now one last bit to create a RESTFul api using Dancer, we create a module called WebApp that would handle all the request that comes through the web. To process the request it takes help from a helper module called WebApp::Helper.
Finally we create a server, we call it, server.pl and looks like:
use Dancer; use WebApp; dance;
We are now ready to start the web app like below:
> perl bin\server.pl
You should see something like below:
[3284] core @0.000007> loading Dancer::Handler::Standalone handler in C:/Perl/site/lib/Dancer/Handler.pm l. 41 [3284] core @0.000535> loading handler 'Dancer::Handler::Standalone' in C:/Perl/site/lib/Dancer.pm l. 366 >> Dancer 1.3072 server 3284 listening on http://0.0.0.0:3000 == Entering the development dance floor ...
Open your favorite browser and point it to http://localhost:3000. You are now ready to play with it.
Let me remind you all this is my first ever blog and my first attempt to write something about Perl. I am open to any suggestions you have.
Awesome! But why not put this out on Github where other people could poke and prod it a bit? Is a neat piece of Perl advocacy.
Thanks! --Johnn
Thanks for your suggestion. I would certainly put it on my public Github repository.
Best Regards,
Mohammad S Anwar
Very nice. As you say, Dancer has good documentation, but working examples of how to do different things -- and different ways to do them -- are a big help too.
Thank you for your post.
A small issue, could you please fix the markup, it turned most of the article into a link.
As I am new to this, I have no idea how to fix this. I would appreciate if you could please point me to right direction where I could learn to fix this.
Many Thanks.
Best Regards,
Mohammad S Anwar
The markup problem in the post is that you have a/ in the closing tag after 'tar ball' instead of /a.
Thank you Aaron for the suggestion. I have fixed the typo in the blog.
Best Regards,
Mohammad S Anwar
Rather than creating the Model::* modules by hand, which can be quite onerous if you're using a large number of tables, have a look at Rose::DB::Object::Loader for generating them directly from the database. There's a few things that it can have trouble with, but generally it's very useful - particularly if your DB's schema is also evolving while you're developing your application.