Recently, I started trying out git to see what the relative advantages and disadvantages of it are over Subversion, SVK, and CVS. I am not quite ready to give up the use of Subversion as the mechanism for sharing my projects with others, if only for the fact that I know more programmers familiar with it than with git (and also for the fact that my web host provides built-in support for Subversion, not git, at this time). Therefore, I’m actually using git as the front-end to access my Subversion repositories, which is quite similar to how I use SVK (and the normal model for SVK use).

The first difference I had to deal with was simply that the command-line is just a bit different. So, I had to map various ideas in Subversion/SVK/CVS into git before I could use it very successfully. Now that I’m using it comfortably, I’m certain I like it better than anything I’ve yet tried and will likely continue to use it over SVK, which was my preference up until now. On the other hand, I don’t think I’ll ever completely give up using Subversion, SVK, or CVS entirely unless and until they become obsolete tools that no one is using.

Adding Changes

Why do I like git over the alternatives? First, it helps protect me from common mistakes. For example, one thing that annoyed me at first is that you have to add any files you change to the list to be committed before committing.

% git add lib/Net/Google/PicasaWeb.pm
% git commit

That seemed a little annoying compared to how SVK lets you commit with a single “svk commit” command and select which files to commit by editting the commit message. Yet, once I got used to it, I realized that I rarely ever have to back out a mistakenly committed file. It only commits those you explicitly ask for. If you’re sure you want to commit everything, you can add whole directories or use the -a switch to commit, but the fact that you have to explicitly make these decisions rather than just committing whatever makes it difficult to make mistakes in what you commit (unless you are in hurry).

Commit by Hunk

Next, I can commit only parts of a file. This feature blew my mind. This should be a mandatory feature for any source code storage system. When I’m making a complex set of changes, but don’t make intermediate commits for whatever reason (laziness, forgot, not sure if what I’m doing in one part really serves the whole yet, etc.), I can perform an interactive patch.

% git add -p
% git commit

When running add with the -p switch, you will iterate through all the listed files (or in this case, all files changes in the repository), and be shown the diff. You can then add individual hunks from the diff to the commit or not. On the latest release of git, you can even edit the diff to pick out individual lines from the hunk to stage and leave the rest out for the moment. This is a killer feature.

Tracking Patches, Not Files

Another nice feature has to do with how git manages to deal with tracking changes. In Subversion, SVK, and CVS the most important unit to work with is the code itself. However, with git, the most important unit to work with is the diff of how the code changed from one commit to the next.

What do I mean? As an example, if I take a project and branch it to work on some complicated feature while the trunk continues to move forward. Then, I merge them when I am done, Subversion, SVK, and CVS handle the merge by diffing the branch with the trunk and then putting all the changes together in a single revision. These will use the history of the trunk and branch in various ways to help resolve problems, but they essentially treat a merge as a single diff. (SVK is a partial exception if you use the “-I” option during merges.)

With git, all the changes of the merge are copied over to the top of the trunk and then you deal with conflicts one diff at a time. This way the entire history gets pulled over from the branch onto top of the trunk, as if the work had been done from the top of the trunk in the first place. You take a little extra time to “rewrite history” this way, but it makes your patches a little more logical.

This same handling of patches works all over the place. For example if you just want to take advantage of some new features placed on the trunk, you can do something called a “rebase” rather than a “merge.” This is the same process as the merge, except all the patches remain on the same branch.

% git rebase master

You can even move the entire branch to a different base point if you want to try your branch out using features still in progress on a different branch:

% git rebase --onto bar master foo

The above command would move all the changes on branch “foo” on to branch “bar” as if these changes had been written for “bar” originally.

Under SVK or Subversion, a merge would be done by pulling in the latest trunk changes over into the branch. This adds a the trunk changes into the middle of your branch as either an individual commit (or as a set of commits with “-I” in SVK).

Work in Progress

Have you ever tried out some code changes and then realized they weren’t going to get you where you want to go? At the same time, though, there are some good ideas here that you don’t want to just throw away. In Subversion you might create a special branch to hold them, but probably not. In SVK, you might create a local branch or something to hold work in progress, but again, probably not.

In git, you can just run:

% git stash

This takes all of the changes you’ve just made and stores them quickly in a special stash. You can then see the stash and recover the latest stashed item using:

% git stash list
% git stash apply

There are a few other commands with the stash as well that are handy, but these are the ones I use most.

Those are a few of the reasons why I really like git. On the other hand, there are some aspects of SVK that are nice, such as the fact that it is very easily extended using Perl (since SVK is written in Perl and written for extensibility). I’ve been thinking about looking into adding features like these into SVK as a fun exercise since I’ve been playing with git. I sure don’t have time to do any of the other of the fun projects I do on my own time, so why not?

Cheers.

I think if I had my way, I would develop tools for developers most of the time. This would be a good implementation of Yegge’s “only build stuff for yourself” principle. The Android project catches my eye because it offers the possibility of being able to get rid of the Microsoft OS on my phone without having to buy a new phone. However, after looking at the site, I’m now more interested in the tools they’ve put together to aid this development.

The first is a tool called “repo”. It’s somewhat similar to a tool we use at work for managing our source repositories. It basically adds some higher level niceties to git and helping connect with code reviews. In addition, it interacts with a nice web-based UI for code reviews they’ve called “garrit”.

Garrit is kind of like a ticket tracker for submitting patches and works almost in reverse of the usual ticket tracker. Normally, you post a problem and then put together a solution. This tool lets you submit a solution and then lets the reviewers determine whether it’s a good idea or not. This is important for a project like Android where it will likely be common for someone to write a patch to get Android working for his particular phone or app and then submit it to the community for general inclusion. It supports the git model for development pretty well.

Anyway, I’m interested in Android and hope some smart folks with better C skills than me can make it work on my phone in the near future, but in the meantime, I think dev tools present some interesting ideas on their own.

Cheers.

I don’t travel away from a network very often, particularly now that I have an EVDO card. However, it is inevitable that when am away from a network (on a plane, in snow storm, on the road) I want to try out a CPAN module or need one that I haven’t yet installed. When this happens and I can’t do whatever it was that I wanted to do because I didn’t have it, I get grumpy. However, thanks to CPAN::Mini, I don’t have to worry about this problem anymore.

% sudo cpan CPAN::Mini
% mkdir -p ~/projects/minicpan

That installs the module itself and sets up the directory for the local repository. Then, I added a nice alias to my shell config:

alias cpansync="minicpan -l $HOME/projects/minicpan -r http://ftp.osuosl.org/pub/CPAN/"

I picked the OSL mirror here since I happen to know the man responsible for admin’ing that mirror. I can then run this to get a copy of the latest and greatest on CPAN:

% cpansync

After that runs, I can run it again any time I want to refresh, which I usually do right before I travel and any other time I want a fresh copy.

Finally, I modified the list of CPAN mirrors to include:

file:///home/sterling/projects/minicpan

Now, whenever I install modules, the modules are installed directly from my hard drive. This is also a bit faster than having to download the modules at install time (i.e., as long as I have already done the download previously).

This setup makes me happy, especially when on airplanes.

Cheers.

I found out about the fact that I would be giving two talks at the Pittsburgh Perl Workshop this week about 2 weeks ago and have been working frantically to get my stuff together since. Well… at least, I worked frantically for the last week. The first week, was not quite frantic. It was more like somewhat diligent, but I did spend a couple nights playing Zelda that should have been spent prepping. Anyway, I got my talks done and I don’t think they were particularly excellent, but I don’t think they went badly (at least, I hope they didn’t). But, this post isn’t really about my talks so much as it is about debriefing PPW 2008. On to the festivities…

Travel To

It all started on a completely average Friday morning of packing… okay, skipping ahead. I flew to Pittsburgh through Milwaukee. In Milwaukee, I was supposed to take a late flight from there, but that wasn’t supposed to me I took off from Milwaukee after midnight. However, the flight the airplane hadn’t even taken off yet from Dallas when we landed. So, I worked more on my slides which weren’t quite finished while I waited. And waited. Finally, the plane arrived and took me to Pittsburgh, where I landed around 2am.

Strange thing about the flight, though. There were only 5 actual passengers on an Embraer 170. For those of you that aren’t airplane fanatics (like me), that’s a plane that seets about 70. There were two flight attendants, the pilot and copilot, and another 4 or 5 airline personnel catching a ride to Pittsburgh. That’s all.

I was the only one that had a checked bag. Uh-oh. When I got off the plane, a baggage handler was asking each of the 5 real passengers if they checked a bag and I said, “Yes.” He said he’d meet me at baggage claim. He met me there, but with no bag. It was lost. Poop. I almost never check a bag and this time I did. Dumb. Oh well.

So, I catch a cab and go on to the hotel and finally get to sleep sometime after 3am.

PPW Saturday

My phone alarm woke me up around 7am. Yeesh. I felt like something scraped off the bottom the mattress, but I got up and showered and got some coffee. I am in a hotel about 1.5 miles from the conference, so I figured I walked. I think this was a good thing as it helped me wake up a bit and it has been a glorious weekend in Pennsylvania. I stopped off to get some antiperspirant and some Listerine breath strips to minimize in odious scents I might be emitting since I was lacking my toiletries.

I made it to Wean Hall on CMU campus and promptly picked up my conference T-shirt and took it to the bathroom to exchange it for the mildly damp shirt I had been wearing that had probably picked up odors from a shuttle bus, three airports, two airplanes, and a cab, not to mention a 35 minute walk on a warm morning with a 30 pound backpack. Okay, so with new shirt donned and odor opposing chemicals applied to my underarms and mouth, I went in to the keynote on Perl 6 in progress.

Perl 6

The keynote was by Patrick Michaud and the news for Perl 6 is good! Yay! For anyone who has followed the drama of Perl 6, you know that some of the history hasn’t necessarily been positive. However, it sounds like things might actually be moving on the right track now. The final release of Perl 6 still expected on Christmas, as it has been for at least a couple years now. But, given Patrick’s report, it sounds like it might actually be a Christmas before my son starts elementary school. (I wasn’t always sure of that.)

Bug Labs

After the first talk, a company called Bug Labs gave a presentation. It was kind of an odd talk I thought since it really didn’t have much to do with Perl (existing APIs are Java), but it was more of a suggestion that Perl hackers could get involved. I’m a bad candidate for that. The product itself looked like an interesting diversion, but nothing I’d be willing to sink that much cash into. I’m not so much a hardware guy anyway.

My personal feelings aside, I have some doubts about the business plan of Bug Labs. It’s nice that they support Open Source, but the viability of the business model is a little questionable to me. The presenter kept saying they wanted to make it so easy that “your mom” could come up with a custom device. First, my mom is not likely to care about a device unless it comes prefab with as few buttons as possible. Second, my mom is not going to put down that kind of cash just so she can create some sort of customized web-cam/motion-sensor/GPS something-or-other. She has better things to do. I suspect she didn’t mean my mom literally, but that doesn’t mean my statements are any less valid for the hypothetically average mom either.

SQLite Extensions

After that was a talk on extending SQLite, which I admit I paid very little attention to because I was still trying to finish my slides for my first talk on Sunday. I thought this sounded interesting and it would be nifty to have more of that in some of the code we do at work, but since we don’t use SQLite for the work I’m thinking of, the talk doesn’t really apply to that.

Data::Rx

Ricardo Signes then gave a talk on something I’d never heard of before, Rx, but I think I’m going to check out. He’s basically put together a data validation system similar to XSD or RELAX-NG, but for general data structures in memory. It’s a really cool idea and I want to see what I might be able to gain from it, so it’s on my short list of things to try out in the near future. The fact that he’s got implementations for it in Ruby, Python, and PHP is also very interesting for interoperability.

Lunch

Next was lunch where I met Dan Klein, a fellow consultant for Grant Street, in person for the first time and had a pretty mediocre chicken marsala, but an excellent salad with fetta cheese, roasted almonds, and strawberries with a raspberry vinaigrette.

Advanced Pattern Matching

Paul Grassie, another co-consultant, gave a talk on regexes, which I again confess I mostly missed to work on my own talk. What material I did catch was a good review and there were bits that were somewhat new, but I wasn’t paying close enough attention to really learn them.

By the way, Paul and Dan work for Tom Christiansen Perl Consultancy. Given what I know of them now (having seen Paul in action and spent part of a day with Dan), I’d recommend their services if you have some need of Perl training for your company.

Network Introspection

This talk I almost completely ignored. There were some things in it that were interesting, but it was mostly for the sysadmins. I was familiar with and impressed with some of what was presented, but I did the system administrator thing already and have turned a new leaf. I’m not going back to the land of putting out fires in the world of hardware.

RDBMS

The next talk was on a database tool called Kioku::DB, which is an interesting idea and something I’m glad to be aware, but not something that will change the way I do my work or hobbies. Again, I’m still working on slides as I glance up now and then and this didn’t really capture my attention.

Email Hates the Living!

Finally, Ricardo gave his second talk of the day on Email. Having myself engaged in mortal combat against the spam monster at one of my first tech jobs and having been a systems administrator, this talk was flipping hilarious. His analysis on the insanity of email and the email specs is right on. For example, “asdf@!#$&” is a valid email address within the To: or From: line of your email, even though such an email couldn’t possibly be delivered. Yet, “asdf@!#$&.” is not. Stupid. It’s a great talk and helps to explain why his CPAN repository is filled with email code, when it doesn’t seem like it should really be quite that hard.

Dinner and Sleep

After that, the Grant Streeters still around headed out for dinner where there was some lively discussion of work and politics. Then, I went back to the hotel room and came up with a Lightning talk, did the final clean up on my slides, and then tried to get more sleep.

The Saga of the Missing Bag

I haven’t finished the story about my bag. Early Saturday, I called Midwest Airlines to find out about my bag. As I mentioned, mine was to be the only checked bag and the handler that I talked to couldn’t find it. He made me out a claim for the bag and said it would be delivered as soon as he could get it to me.

When I called Midwest, the conversation with the woman went something like this:

Me: Hi, I’m calling to find out about my missing bag.
Woman: What’s your name?
Me: Andrew Hanenkamp. H-A-N-E-N-K-A-M-P.
Woman: Mr. Hanenkamp? Yes, your bag came in on your flight. Why didn’t you pick it up?
Me: Um, because the guy who said he was going to pull it out of the plane said he didn’t find it and gave me a baggage claim ticket.
Woman: Okay, I’m very busy right now, I will try to get them delivered to you hotel. Can I get your number?

I gave her the number and then finally was able to get back with her during lunch. This conversation went something like this:

Me: Hi, I’m returning a call made to my cell phone?
Woman: Who is this? Is this Mr. Hanenkamp?
Me: Yes, I believe you have my bags, have they been sent to my hotel yet?
Woman: Well, your bag was here last night. My supervisor wants to know why didn’t you pick it up last night. It was here already.
Me: I know. As I told you before, the guy who pulled it out of the plane told me it didn’t come.
Woman: Hmm. Okay. Umm. Did he give you a baggage claim ticket?
Me: Yes. I have it in my wallet. (Thinking, do you want me to shove it through the phone?)
Woman: Okay, well, I guess I can have the delivery service take your bag over. Which hotel are you at? Do you know the zip code?
Me: [chuckle] Um, no, I don’t generally memorize the zip codes of the hotels I’m staying at.

Anyway, so when I got back, I had my bag and was finally able to change into completely fresh clothing and brush my teeth and such. Ah.

Sunday

I walked over to Wean Hall again after picking up my coffee and started out in the Rakudo Perl talk.

Rakudo Perl

This talk was also given by Patrick Michaud and I went to it rather than the Moose talk because I’m already somewhat familiar with Moose and because Perl 6 and Parrot are something I’d like to volunteer my time on. Perhaps I will at some point, but I have too many other things I’m doing that I’m more immediately interested in. I don’t have any excuse for not joining for reasons due to not knowing how now, though. Patrick went over all the sorts of things someone wanting to contribute might want to do to get started.

Managing Open Source Projects

Next I went to this talk by Tom Lane rather than attending Schwern’s talk on the y2038 bug. The talk was moderately interesting since Tom Lane is a Red Hat employee who spends most of his time contributing to PostgreSQL. It was interesting to here the differences between how Perl is managed and PostgreSQL, but I confess, I was again distracted, but this time by a bug report on one of my CPAN modules.

Data Structures

This was another talk by Paul Grassie and at a very introductory level. I don’t think he covered anything I don’t use on a nearly daily basis, but I was still working on bugs on my CPAN module. I did note that Paul has a very soothing voice and since I’ve only had about 8 hours of sleep total in the past 48 hours, it was making me a bit sleepy.

MooseX::Tour

Next was Jonathon Rockway’s talk on MooseX extensions. There are some pretty cool extensions to Moose available for dealing with various customizations to your meta-programming code. I’d recommend looking over his slides when they are posted on his blog. There’s some interesting things in there.

Lunch

We had more lunch. I got to meet Tom Welsch’s kids, since Tom brought them with him as he did a little light recruiting for Grant Street. I had more yummy salad and a decent sandwich (at least for having been catered).

Jifty Talk

I gave and got through my whole talk on Jifty. I’ve posted the slides, which is enough summary.

Prophet

I watched part of Kevin Falcone’s talk on Prophet and this is another one of those things that I have got to get my hands on in the near future. Qublog, in particular, could benefit from what it does very nicely.

Perl REST

Again, I gave this talk and the slides are posted.

Method Signatures

Lastly, I attended the talk Schwern gave on his new method signatures class. It’s pretty nice overall, but I’m a little hesitant to actually use it. His point about there being 240,000 extra lines of code that can be taken off of CPAN because of it is well-taken, but I’m not quite convinced to actually use it yet. On the other hand, the parser module that Matt Trout wrote, Devel::Declare, which has some interesting possible implications for the DSL work I want to do with Jifty.

Lightning Talks

Most of the lightning talks were great, mine excluded. I fail.

Ricardo gave a talk on Dist::Zilla, which I am also adding to my short list. It’s kind of a replacement for Makefile.PL and Module::Starter and Module::Release and such, but does some very smart things. If I find out that it’s extensible and mostly makes sense when I take a first hand look, I’ll likely be using this to manage my modules in the future.

Kelli Ireland gave a talk on the orange shirt that’s been traveling with various members of the Perl community to exotic destinations and offered it to anyone going somewhere interesting if they will take pictures.

There was a talk on going Sixty to Zero in Perl (a play on the Zero to Sixty tutorial given). This talk was great in that it showed how very readable Perl can be turned very unreadable if someone wishes to do so deliberately in order to maintain job security. It was a very good example of why serious Perl developers don’t understand why Perl gets kicked in the face so much when it is not difficult to write good Perl code if you actually try to do so.

Probably the most memorable lightning talk, though, was the LOLCAT history of Perl. Unfortunately, there’s no way such a talk can be translated into this summary in any useful fashion, so I will just say, that it was awesome.

After that, I skipped out because I’m sleepy and should have been asleep already, but decided to write this instead… Okay, so I think that does it for PPW 2008. This is Sterling Hanenkamp signing off. Good night and God bless.

I gave my talk on REST at the Pittsburgh Perl Workshop today. I think it went alright, but I’m sure it was dreadfully boring. If I ever give the talk again, I’m going to have to liven it up a bit and speed up the pace. For anyone that attended the talk, I would be interested to have your feedback, so please feel free to post it here.

Here are the slides, as promised:

Making Your Perl REST
View SlideShare presentation or Upload your own. (tags: perl rest)

Again here are links to the sample implementation files:

Cheers.

I just wanted to make a quick post to note that I will be in Pittsburgh this weekend speaking at the Pittsburgh Perl Workshop 2008. I will be giving two talks on Sunday afternoon:

Also featured at the conference will be talks by a couple of my coworkers:

I’m mostly done with one set (REST) and started and somewhere around 25% done with the preparation I need to get done for the other set, which will include a shameless plug for my other project.

This isn’t the first time I’ve given a 50 minute talk, since I taught a class, but this is a much different format than that. Since I’m attempting to re-use the excellent work of others (particularly Jesse Vincent and Audrey Tang on the Jifty talk), I hope I will do alright.

Cheers.

At my current job, I have quite a few more important appointments on a regular basis that I’ve had since I was teaching courses at K-State. As such, I’ve resurrected my dedication to the calendar. I have finally gotten a setup working that seems to do the job of allowing me to keep a good calendar, keep my wife informed, and keep my phone informed.

To do this, I’m using the following:

This is working pretty well. The weakest link in this setup is The Missing Sync which works, but is an absolute steaming pile when it comes to stability. It crashes at least 50% of the time I sync. Fortunately, it usually recovers if I force quit and unplug/plug my phone. If there’s anything else out there the next time I’m looking to buy something like this, I’ll try it instead unless they can get this fixed.

One thing I’ve discovered is that the integration with Apple Mail and iCal is wonderful. I can very easily create appointments by hovering over dates mentioned in an email, click on the popup that appears, and select “Create New iCal Event…” This makes keeping track of coworker’s vacation time and the downtime schedule very easy.

Cheers.

I have a Mac and I listen to music in iTunes most of time. After quite a bit of experimentation I have, I think, finally come across a way of creating a play list that allows me to tolerate iTunes. I don’t like listening to my music in order. I’d like it to play randomly. On the other hand, random typically means I get one or two songs I don’t particularly like that come up often and some songs I do like getting played almost never. This is never what I want, but this is exactly what the useless “Party Shuffle” feature of iTunes. I hate it. Even with the “don’t play a song by the same whatever” settings set, it still manages to do so too often for my to tolerate.

My solution is to put together a play list that contains a set of music I like to listen to and then I create a smart play list based on it. When configured correctly, my play list will play all the music I want to hear regularly, but not too regularly. Here’s how I do it. I create a smart play list and set it to match all of these rules:

  • First, I add the rules that pick out genre or off of another play list as the source, plus any other modifications like minimum rating.
  • Second, set a rule that requires the Last Played date is not in the last X days, where X depends on the size of the source play list. For example, my “Top Music” list contains around 715 songs with around 1.9 day play time. I set the limit to at least 7 days, for this list.

After that, I tell it to limit the play list to Y items selected at random. For the “Top Music” play list, I use 75 items. I then make sure it’s Live Updating in case I add more music.

Finally, I play the list on shuffle. Since I’ve started playing my music this way, I find that I listen to all of the music in the list every month or so and I never hear a single song too often and it’s completely random.

What I really wish was that Party Shuffle would work the way I think it should. If I want to see the next 25 songs ahead, I want it to guarantee it won’t duplicate anything within that window. If I could then have it try to fit in songs I haven’t heard in a while, but prefer the higher rated songs, that would be great. It wouldn’t have to be perfect, but iTune’s play list options are abysmal.

Cheers.

I just finished reading this blog post and was convinced for a few minutes that this guy was stalking me even though I have no idea who it is. Fortunately, the references about class and school allowed me to relax that he’s actually just stalking my long lost twin.

Thanks to Randall for passing that link on to me. It’s a little scary how accurate it describes me and, like Randall, I have to confess a little embarrassment at some of the harsher bits of the analysis because it’s very close to the mark, even down to the mention of specific details.

Cheers.

Part 1 of this article was posted on onlamp.com. Due to changes in the format of O’Reilly’s online publications, they are no longer interested in Part 2, so I have published it here. Sorry for the delay but it took some time to contact the editor to learn all this.

In my previous article, I described the process of building a RESTful web API from the server-side. This article will describe how we write the client to the web services server provided in the first article.

The source code for the client and server described in this article is available by saving the following links:

There are some instructions on how to install them in comments in each file, but you’re mostly on your own. I can say that they should work (do work for me) if installed correctly and if the required libraries are in your library path. Sorry that I haven’t made these easier to use.

RESTful Client

The RESTful server written in the previous article helps me track the books in my library. This time, we’ll look at a command-line client that takes advantage of the API. The principles applied to build this client could be used to in your web application to access web services APIs provided by third parties or to build a GUI application or anything else. A command-line just provides a good simple interface with which to demonstrate.

The command-line script is named book and operates through the use of subcommands. For example, to list all the books in the system, you can run:

./book list

In cases where a new book is added or updated, you specify the update using a file name.

./book update 1-56563-833-6 treasury.yml

Without further ado, let’s jump into the code.

Setting up the Client

Before getting into the commands themselves, there is some setup performed by the script. First, we have a constant named HOST. This constant is just the URL of the REST API server.

I’ve also defined to additional helper functions that will show up throughout this article. The first, barf(), is called whenever an error occurs. Since our server returns errors as HTML, it just pulls title of the error from the HTML header and the rest of the error message from the first paragraph. The second helper function is slurp(), which is really nothing more complicated than the function by the same name in File::Slurp (but without an additional dependency, which I was attempting to avoid for the simple demo). All this does is suck in all the text of a named file and return it as a scalar.

The last bit of setup is that I’ve initialized one global variable named $ua for convenience. This variable contains a freshly initialized LWP::UserAgent object. The only library from CPAN this program depends upon is libwww-perl. I’ve also imported some helpers from HTTP::Request::Common, but we’ll get to that in a bit. Now, let’s talk about the interesting stuff.

Listing Resources

The first and simplest command we can run is to simply check to see what resources are available. You can see all the books stored by listing them using this command:

./book list

Calling this command causes the script to run this bit of code:

# GET /=/model/book
my $response = $ua->request(GET HOST.'/=/model/book/id');

# On success, find the link and print them out
if ($response->is_success) {
    my @links = $response->content =~ /\bhref="([^"]+)"/gm;
    for my $url (@links) {
        my ($id) = $url =~ /([\d-]+)$/;
        print "$id: $url\n";
    }
}

# On failure, barf
else {
    barf $response;
}

Our first act is to grab a list of books from /=/model/book/id. As we saw in the previous article, this should return an HTML file containing a list of links as part of the API. If the request was successful, we pull all the links out using a regex and print them out to the end-user. If the request fails, we barf.

The key bit of code here is all within the call to the GET subroutine, which is exported by HTTP::Request::Common. This performs all the extra work we need to build a standard GET request. Another alternative is to use the get() method of LWP::UserAgent, which would look very similar:

my $response = $ua->get(HOST.'/=/model/book/id');

Moving on, I hope I haven’t turned your stomach with how cheaply I’ve parsed the URLs and IDs out. This is not an ideal use of regex, but it does the job. If I were to do this the right way, I ought to use a decent HTML parser (I’m partial to HTML::TreeBuilder) to pull the links out more carefully. Another solution would be to alter the server so that it returned the links as a YAML file and then parse apart the YAML data to get the information I want. I’m lazy and wanted to avoid additional module dependencies at all cost on the demo, so I do it this way.

This will return a list of IDs, which may be ISBNs or just a number, which isn’t terribly useful. A simple enhancement to the system would be to change this to use the “title” field or something else, but we’d also have to enhance the server to support that.

Reading a Resource

Once we know what resources are available by the list, we may then want to check one out to get more information about it. We can do this using the read command. For example,

./book read 1-56563-833-6

As you will recall from the server, we can read data using a GET request to /=/model/book/id/<ID>. This is what we do when the read subcommand is executed:

my $id = shift @ARGV;

# GET /=/model/book/id/[id]
my $response = $ua->request(GET HOST.'/=/model/book/id/'.$id);

# On success, print the file
if ($response->is_success) {
    print $response->content;
}

# On failure, barf
else {
    barf $response;
}

We grab the ID given from the command line and use LWP::UserAgent to GET the book resource we’re interested in. On success, we then print the file out and on failure we barf.

If we wanted to do something more interesting with the resource file like present in a form or place it into a table or something, we’d use a YAML parser to decode the data and then manipulate it.

Creating a Resource

Now that we’ve looked at the resources in our (presumably empty) database, let’s look at how we added them. The first command to consider is, of course, for creating a new book record.

./book create treasury.yml

The command slurps up the file you name and uses it to POST to /=/model/book to create a new book record. We then scan the response to make sure we know what ID was assigned (because, if you’ll remember, not all books have ISBNs, so the server provides an alternate identifier in such cases).

my $file = shift @ARGV;

# Slurp up the contents of the given filename
my $book_data = slurp $file;

# POST /=/model/book
my $response = $ua->request(POST HOST.'/=/model/book',
    'Content-Type' => 'text/yaml',
    Content        => $book_data
);

# On success, return the new ID assigned to the resource
if ($response->is_success) {
    my $url = $response->header('Location');
    my ($id) = $url =~ /([\d-]+)$/;
    print "$id: $url\n";
}

# On failure, barf
else {
    barf $response;
}

As you can see, this is exactly what we’ve done. Since the server requires the data to be specified as text/yaml, we’ve made sure to note that here. If the file is improperly formatted, the server will take note and return an error status, so I’m not being too picky about making sure the data is clean. However, you might want to make sure your data is sane before sending it in such cases just to avoid potential problems.

The other important detail to notice here is how we get the ID assigned to the resource back. We do it by checking the Location header. This is because we’ve build the server to return a 201 Created status with a Location header referring us to the new resource location. If we were to perform an immediate GET on that location, we’d get the resource record we just saved back from the server. In fact, that’s probably what I should do. Instead, I’ve just ripped the ID off of the URL since I know what it will look like. This is a minor breach of the opacity principle of URIs, so if you’re sensitive about such things, I recommend you take the extra step and pull the ID from the returned YAML data.

Updating a Resource

Once we’ve added a resource, we might want to update to correct a typo or submit additional information to the record. We can do this by running:

./book update 1-56563-833-6 treasury-updated.yml

As with the create command, we slurp up the file argument, but instead of a POST, we PUT. We also use the URL included the given ID.

my $id   = shift @ARGV;
my $file = shift @ARGV;

# Slurp up the given file name
my $book_data = slurp $file;

# PUT /=/model/book/id/[id]
my $response = $ua->request(PUT HOST.'/=/model/book/id/'.$id,
    'Content-Type' => 'text/yaml',
    Content        => $book_data,
);

# On success, just announce success
if ($response->is_success) {
    print "Updated $id\n";
}

# On failure, barf
else {
    barf $response;
}

We again make sure to let the server know we’re passing it a YAML data file. Here the returned result is pretty empty, so we ignore everything but the status code and just return a success message. If we had implemented resource renaming on the server using PUT, we would probably need to watch the response for the new resource URI to make sure we fetch the new ID. Since we didn’t, we don’t.

Deleting a Resource

Finally, when a book gets lost or sold or just thrown away, we can delete it from the library. From the command line, this looks like this:

./book delete 1-56563-833-6

Internally, the command is again very simple. This time, we just need to post a DELETE to the appropriate URL, /=/model/book/id/<ID> and check to see if it succeeded or not.

my $id = shift @ARGV;

# DELETE /=/model/book/id/[id]
my $response = $ua->request(
    HTTP::Request->new( DELETE => HOST.'/=/model/book/id/'.$id )
);

# On success, announce it
if ($response->is_success) {
    print "Deleted $id\n";
}

# On failure, barf
else {
    barf $response;
}

First thing to note is that here we build the DELETE request ourselves. This is because HTTP::Request::Common did not provide a shortcut for DELETE when I originally wrote this client. I am happy to say that such a method exists as of 5.814 of libwww-perl. In case you aren’t able to use the latest version for some reason, this is how you live without. Fortunately, it’s not difficult to do this on our own.

Other than that, this should look remarkably similar to the update command minus the slurpy file action.

RESTful Resources

Now that you know the basics of building a REST server and client, you’re ready to move on to bigger and better things. Here are some resources for learning more about REST, for creating and using REST interfaces without building one yourself, for enhancing your REST interfaces, and some existing REST interfaces you might want to model or take advantage of.

RESTful Documentation

If you’re going to build a REST interface or work with one, it is helpful to find some details on what such things are commonly involved with. The most commonly referred to reference on the subject is the REST Wiki. If you want to know the general outline of how some guys that think a lot about REST APIs in the abstract, this is a good resource.

An even more vital resource is the actual HTTP standard. It describes what the various request types and response types are for and how user agents should expect to deal with them. Since REST is tightly bound to HTTP, sticking to the proper behavior in HTTP is very important. Therefore, I recommend becoming familiar with RFC 2616, which helps define the HTTP 1.1 protocol itself.

RESTful Tools

If you don’t want to mess so much with the code and just build on the foundation already laid by someone else, the best tool for the job that I currently know of is OpenResty. This is a stand-alone REST database system. It’s essentially a middleware platform for accessing a database over HTTP and is a pretty good system to emulate.

I’m also partial to the REST plugin provided by Jifty. Just by implementing a few models and actions with Jifty, you get a REST interface to them for free. See Jifty::Plugin::REST for the server side implementation and Net::Jifty for the client.

Both of these tools have a very similar feel to the implementation I’ve built for these articles because I like the style of Jifty’s implementation.

RESTful Extensions

The most significant RESTful API add-on I know of is OAuth. This tool provides a standard mechanism for sharing protected data between disparate services via REST. For example, let’s say you’re building an application that automatically sets the profile photo for several different social networking sites. You don’t want to store these photos, you just want to grab them and update a bunch of social networking sites. You could use OAuth to allow your users to grant you permission to access their Flickr or Picasaweb accounts without asking them for their username and password, which is one of those things that serious privacy advocates go bonkers over.

There are some big players implementing this and I’d love to see more mashups using this rather than asking me for my username/password to get photos or load contacts.

RESTful Services

There are lots and lots of RESTful web services available. However, I will highlight just a few that I have worked with personally in the past.

The first two are by Amazon. Amazon’s Web Services are all REST based, but the one’s I’ve worked with include S3 and EC2. With Amazon S3 you can store files on their services and be charged in micro-payments for just the storage you use and the amount of data transfer (which is pennies per Gigabyte). With Amazon EC2 you can run Linux-based servers that are started and stopped and manipulated using a REST-based service. These are again paid for in micro-payments by the hour (starting around 10 cents / server hour last I knew). There are Perl libraries already available for manipulating both of these without having to know the API directly too (search CPAN for Amazon).

The other I have worked a little bit with is Intuit Quickbase. Quickbase allows you to build database applications with a point-and-click interface. You can then pull and push data in and out of the system using a RESTful interface.

The last one I want to mention is Hiveminder. Hiveminder is a web site for managing your to-do list. Hiveminder provides a number of different interfaces including an IMAP server interface and a RESTful Web API. Hiveminder is built with Jifty and has a special sub-class of Net::Jifty available for accessing the web API, Net::Hiverminder.

Conclusion

There’s more that could be said and more resources I’d like to refer, but I think this article is plenty long. Adding a RESTful interface to a web application is a relatively simple thing to do and is great for giving folks a clean way to access and manipulate your application’s data.

Please feel free to comment here and I will try to answer any other questions or comments.

Cheers.