Consuming RESTful Services with Perl

In my previous article I described how to create board game images using Image::Magick, thus allowing you to design board games using Perl. This time I want to show you how to upload those images to The Game Crafter so you get get a professional copy of the game manufactured.

In the last article I created a board game version of the video game called The Lacuna Expanse. This time I'll show how to upload those images to the site to create a custom board game. Don't worry if you're not ready to create a board game or if you'll never be ready; the principles of designing a useful API and using it apply to all sorts of services you might want to use, from weather tracking to stocks to medical systems. I picked games for two reasons. One, me and I team just built this system, so it's shiny and new and I've learned a lot. Two, games are more fun (and visual) than showing how to record invoice information in a RESTful ERP application.

Getting Ready

First, get yourself a copy of TheGameCrafter::Client. It's a Perl module that makes it trivial to interact with The Game Crafter's RESTful web service API. When you use TheGameCrafter::Client; it imports tgc_get(), tgc_post(), tgc_put(), and tgc_delete() into your program for easy use. Good APIs are descriptive and obvious. From there you can have a look at The Game Crafter's developer documentation to do any custom stuff you want. Good APIs have useful documentation.

You'll also need to activate the developer setting in your TGC account, and request an API key. Good APIs demonstrate security in authorization and authentication.

A Little about The Game Crafter's API

TheGameCrafter::Client is just a tiny wrapper around our RESTful web services. I designed the web services atop Dancer and DBIx::Class. My goal with this was to build a very reliable and consistent API not only for external use but internal. You see, the entire TGC web site actually runs off these web services. Not only that, but these web services tie directly into our manufacturing facility, so they are controlling the physical world in addition to the virtual. Good APIs allow you to build multiple clients with different uses. (They don't require multiple clients, but they don't forbid it and do enable it.)

With Lacuna, I built JSON::RPC::Dispatcher (JRD), which is a JSON-RPC 2.0 web service handler on top of Plack. I love JRD, but it has two weaknesses, one of them fatal. One weakness is that you must format parameters using JSON, which means that it's not easy to just call a URL and get a result with something like curl. (Good RESTful APIs allow multiple clients. If you can't use curl, you probably have a problem.) The fatal weakness of JSON-RPC 2.0 is that there is no way to do file uploads within the spec. The Game Crafter is all about file uploads, so that meant I either needed to handle those separately (aka inconsistently), or develop something new. I opted for the latter.

With TGC's web services I decided to adopt some of the things I really liked about JSON-RPC, namely the way it handles responses whether they be result sets or errors. So you always get a consistent return:

{ "result" : { ... } }

{
   "error" : {
        "code" : 404,
        "message" : "File not found.",
        "data" : "file_id"
   }
}

With TGC I also wanted a consistent and easy way of turning DBIx::Class into web services through Dancer. I looked into things like AutoCRUD, but I'm not a fan of Catalyst, and it also took too much configuration (in my opinion) to get it working. I wanted something simpler and faster, so I decided to roll my own. The result was a thin layer of glue between Dancer and DBIx::Class that allows you to define your web service interface in your normal DBIx::Class declarations. It automatically then generates the web services, databases tables, web form handling, and more for you. This little glue layer is now in use in all web app development within Plain Black, and eventually we'll be releasing it onto CPAN for all to use for free. The best part of that is that you know you're getting a production-ready system because it's been running The Game Crafter and other sites for over a year now. (Good APIs are often extracted from working systems.) More on that in a future article.

Let's Do This Thing Already

Before you can make any API calls, you need to authenticate.

 my $session = tgc_post('session',{
   username    => 'me',
   password    => '123qwe',
   api_key_id  => 'abcdefhij',
 });

Before you can start uploading, fetch your user account information. This contains several pieces of info that you can use.

 my $user = tgc_get('user', {
   session_id    => $session->{id},           # using our session to do stuff
});

Think of TGC projects like filesystems: you have folders which contain folders and files. First create a folder, then upload a file:

 my $folder = tgc_post('folder', {
  session_id  => $session->{id},
  name        => 'Lacuna',
  user_id     => $user->{id},
  parent_id   => $user->{root_folder_id},  # putting this in the home folder
 });

 my $file = tgc_post('file', {
  session_id  => $session->{id},
  name        => 'Mayhem Training',
  file        => ['mayhem.png'],         # the array ref signifies this is a file path
  folder_id   => $folder->{id},       # putting it in the just-created folder
 });

Assuming at this point you've uploaded all of your files, you can now build out your game. The Game Crafter has this notion of a "Designer", which is sort of like your very own publishing company. Games are attached to the designer, so first you must create the designer, then the game.

 my $designer = tgc_post('designer', {
  session_id  => $session->{id},
  user_id     => $user->{id},
  name        => 'Lacuna Expanse Corp',
 });

 my $game = tgc_post('game', {
  session_id  => $session->{id},
  designer_id => $designer->{id},
  name        => 'Lacuna Expanse: A New Empire',
 });

With a game created and assets uploaded, you can now create a deck of cards. This is pretty straight forward just like before.

 my $deck = tgc_post('minideck', {
  session_id => $session->{id},
  name       => 'Planet',
  game_id    => $game->{id},
 });

 my $card = tgc_post('minicard', {
  session_id => $session->{id},
  name       => 'Mayhem Training',
  face_id    => $file->{id},
  deck_id    => $deck->{id},
 });

You have probably noticed already how closely this resembles CRUD operations, because it does. Behind the scenes, who knows what TGC does with this information? (I do, but that's because I wrote it.) It doesn't matter to the API, because all of those details are hidden behind a good API. Good APIs expose only the necessary details—in this case, the relationships between folders and files and between designers and games.

You can also see that the API is as stateless as possible, where the session identifier is part of every API call. It's easy to imagine a more complicated API which hides this, but I stuck with the bare-bones REST for at least two reasons: it's simple, and it's easy to see what's happening. Someone could build over the top of this API if desired. Good APIs allow extension and further abstraction.

Just like that, you've created a game and added a deck of cards to it. There are of course lots of other fancy things you can do with the API, but this should get you started. I wouldn't leave you hanging there, however. I've open sourced the actual code I used to create the Lacuna Expanse board game so you'd have something to reference. There's also a developer's forum if you have any questions. Good luck to you, and happy gaming!

Visit the home of the Perl programming language: Perl.org

Sponsored by

Monthly Archives

Powered by Movable Type 5.13-en