Programming

Rails Misapprehensions: Understanding RESTful PUT and POST

Friday, December 31st, 2010

In the last post I talked about the rest in REST, beyond the four major verbs. Before getting completely wasted at the tonight’s new year party I’d like to quickly illustrate my understanding of two HTTP verbs and how to think about them in a RESTful mind.

While GET and DELETE are pretty obvious, a few points really bothered me with PUT and POST.

  • What exactly is the difference between POST and PUT? In CRUD contexts, the first usually seems to be mapped to create, whereas the latter seems to be the update pendant. But that is not the end of the story!
  • How do I implement these verbs in my Rails controllers? Is there some standard, best practices, or something?
  • They say PUT is idempotent – that’s awesome, however, what the heck does that mean?

Help! I’m idempotent!

Let’s explore POST first, which is not idempotent. I wrote a resource to categorize photos I have on my hard-drive, where I simply can add photos to categories.

Here’s how I get the textual representation of the party category (with Restfulie, the one and only REST engine for Ruby).

res = Restfulie.at("http://localhost:3000/photos/party")
puts res.accepts("text/csv").get!

The category doesn’t contain too much pics, as I’m not partying enough:

IMG_0056.JPG, jpg
Michal_drinking.png, png

To add another picture to the party resource, sorry, party category, I could use POST.

res.as("application/jpg").post!(binary_jpg)

Don’t care about how we POST and which format – just notice that we are POSTting to the party resource. This results in another picture categorized in “party” (a polite controller would redirect us with a 201 to the new photo resource).

Multiple POSTs, duplicate content!

Now if I do that 3 times in a row, what happens?

3.times { res.post!(binary_jpg) }

We can see the non-idempotent effect of POST right away.

IMG_0056.JPG, jpg
Michal_drinking.png, png
Nick-on-fire.png, png
Nick-on-fire_2.png, png
Nick-on-fire_3.png, png

The last embarrassing picture was added three times. Since we repeatedly POSTed, we have to take into account that things might be duplicated.

If POST duplicates, can I simply use PUT?

Now, a common deception is allowing users to PUT single images to the /photos/party resource. In the best case you’d simply obfuscate the RESTfulness of your API. In the worst case you’d destroy your party picture collection (depending how you wrote your serving controller)!

I’d like to show how a correct PUT could look like. After that, we discuss why.

PUTting – done right!

Using the idempotent nature of PUT I should be able to insert the new photo only once, even if I PUT repetitively. Here’s the client code.

res= Restfulie.at("http://localhost:3000/photos/party").
  accepts("application/zip")
 
pics = res.get!
pics.unzip!
pics << binary_jpg # add the new photo
 
# and PUT it back:
res.put!(pics.zip!)

Does that look confusing? I guess it does. What am I doing here?

  1. I retrieve all photos categorized in “party” as a ZIP file
  2. then I unzip and add the new photo (for simplicity I simply assume there are methods like #zip! and #unzip! around)
  1. last step is PUTting back the grown ZIP archive

That’s how PUT is intended to work. Let’s discuss.

It’s all about entities…

I really had a hard time understanding where these semantics origin from until I read this fantastic summary (any cite following from this page).

In RESTful architectures we have to distinguish between entities and container resources.

A typical entity is the photo resource.

  • POSTing to /photos/IMG_0056.JPG doesn’t make sense here – should we append another picture to the existing? No, non-sense.
  • However, it is absolutely conclusive that a PUT would overwrite the original picture.

…and containers.

Our “party pictures” resource is a stereotypical container resource.

  • as “POST’s job is simply to [...] add something to a container” it is obvious that POSTing to /photos/party expects a new image binary (or whatever) which is added to the party category.
  • “If you PUT to a container, you are attempting to overwrite the state that was constructed from all the previous POSTs to it” – I couldn’t find better words to describe that. A PUT to /photos/party replaces the existing collection with the one you send.

With that in mind, it should be pain if you allow people to PUT single images to /photos/party – since your controller (should!) expects a complete image collection!

Conclusion

Think of POST as in adding a new entity (often to a container). When you hear PUT, keep in mind that PUT is more like replacing the addressed resource entirely with the new data you send.

How to do that in Rails is worth another post – in 2011. Cheers and Happy New Year!

Haml breaks pre indentation

Thursday, September 23rd, 2010

Haml has a feature called “Whitespace Preservation” which usually tries to nicely indent your markup. This is great.

However, sometimes it gets in your way – especially when it indents your <pre> paragraphs wrong.

I had a setup like

%p
  Here, some code!
  = render_some_code

where #render_some_code would return some markup.

def render_some_code
  "<pre>include 'cells'ninclude 'apotomo' /pre>"
end

[The missing < before /pre is intentional as it breaks this writing, haha.]

I expected the render output to be …nice.

Here, some code!
include 'cells'
include 'apotomo'

Nevertheless, it turned out to be even nicer. Haml’s nice indentation striked.

Here, some code!
include 'cells'
  include 'apotomo'

I found this delicious post by Chrissy Eppstein and in turn read the haml docs on whitespace preservation.

Using Haml::Helpers#find_and_preserve, it works like a charm now. I don’t know why, neither how, but it works.

include Haml::Helpers
 
def render_some_code
  find_and_preserve "<pre>include 'cells'ninclude 'apotomo' /pre>"
end

Releasing with Jeweler

Saturday, April 17th, 2010

I love jeweler for releasing my gems, however I tend to forget how it is working, so here’s my release workflow.

1. Bump and Commit

Bump the version (usually in lib/a_perfect_gem/version.rb) and git commit my latest changes

2. Doublecheck

git status to check if my working tree is clean

git status
# On branch master
nothing to commit (working directory clean)

Otherwise jeweler will complain

$ rake release
rake aborted!
Hey buddy, try committing them files first

3. Release

Finally do

$ rake release

which will

  • tag the commit with "v#{A_PERFECT_GEM::VERSION}"
  • push the commit(s) to origin
  • push the tag to origin
  • build the gem
  • push the gem to gemcutter

Props to [technicalpickles].

Perl CGI Scripts are cached after switching to mod_perl

Tuesday, December 22nd, 2009

I recently had to port a very old perl project to a new server, which is running mod_perl- that made me some headache as I didn’t know anything about that environment.

Pages with dynamic form input from CGI::param suddenly seemed to be “cached”, the script did process old variables and emitted wrong output. After diggin’ into mod_perl with this great article the solution was quite easy.

mod_perl somehow keeps a persistent process environment, thus restoring variables declared with my. As I didn’t want to rewrite the whole thing I simply changed lines like

my $type = param("type");

to

local $type = param("type");

and everything works fine and “uncached”. I know there are several pitfalls with local again, anyway, I’m not into mod_perl, things seem to work and a 10-years old medieval project’s running again.

Painless text-editing with Scribes 0.4 on Ubuntu

Friday, May 8th, 2009

Colleagues keep laughing at me.
It seems that I missed the point in a programmer’s life where he faces a shimmering light at the end of the dark terminal tunnel, where he suddently gets enlightened… and switches to eclipse or Textmate.

Being an IDE-reject I’m used to work with bare-bones text editors, which support syntax-coloring, a bright background and a few well-established keyboard shortcuts like Cmd+c Cmd+v.

That’s all I need.

Ever since I can remember I disliked IDEs and how they suppressed my way of organizing files, tools and minds. And they are slow.

The last 4 years I worked with nedit and my own small file-browser kebap. Two weeks ago me and my colleague Felix discovered scribes, a text-editor for Linux written in Python. Dozens of text-editor came and went away in my life, but for some reasons I really like scribes. Some of its key features I already love are

  • streamlined workflows with a simple and clean UI
  • jump to files with the F9 file-dialog by typing their name
  • code templates which can be triggered while typing
  • character pair completion -yeah i hate to close a bracket and move back the cursor by hand
  • word completion while typing remembers phrases you typed, like long function names and cryptic variables
  • sufficient syntax-coloring for Ruby and PHP (well that could be better)

I really was distracted by the tab-less UI first. “What a mess!” came to my mind. A couple of days later I was conviced that the arrogant attitude of scribes is… cool.
It’s useless to organize your docs in tabs, the more docs you open, the sooner you forget which tabpanel holds the code file you’re looking for. So why not let the F9 file browser keep track of all those files?

Today I noticed that I had 46 opened scribes documents – each in a separate window – while programming at work. Since I simply hit F9 and type in a few characters to jump to the file I completely forgot the “need” for MDIs, tabs, project managers and other “tools”.

Enough praising, let’s hit the keyboard.

Installing scribes 0.4-dev on Ubuntu Jaunty

The 0.3 version shipped with Ubuntu has some bugs, so I recommend the 0.4 version which is almost stable.

sudo apt-get install bzr libglib2.0-dev gnome-common
bzr branch lp:scribes
cd scribes/
./autogen.sh
make
sudo make install

When starting scribes in a terminal, you might get a python exception bitching about
ImportError: No module named gtksourceview2

Well, just do

sudo apt-get install python-gtksourceview2 python-gnome2-desktop-dev python-gnome2-extras-dev

and have fun experiencing a smart, but not too smart editor. Thanks, mystilleef!

Git Cheatsheet

Saturday, December 20th, 2008

Branching

If you’re planning to

  • change huge parts of your code at once
  • introduce a complex new feature or another API
  • switch easily between different – simultaneously running – development processes of your project (actually, that’s called a branch)

you’re better off creating a new branch. As soon as you switch to this branch, the former version won’t get touched anymore. You can easily merge back the changes from the new branch to your master version.

First, list the local branches

git branch

Creating a branch
You start by creating a new local branch

git branch dynamic

we call the new branch dynamic.

Then switch to your new branch. The code will be the exact state when you left the former branch.

git checkout dynamic

You can now apply changes, commit and push to your new branch.

Don’t forget to push the new branch to your remote repository

git push origin dynamic

Merge the branch back
After you think your changes should go back to the master branch, merge ‘em, where the newer will supersede all of master

git checkout master
git pull . dynamic
git push

{is git pull . dynamic + git push =?= git merge dynamic}

Tagging

I often explain a tag in git as a bookmark which lets you return to some specific version of your code. As you can have an unlimited amount of tags, you can have as many bookmarks as you need.
So when you want to take a snapshot of your code saying “if I had releases, and would package my code, this version would be packaged as 2.2.1.tar.gz” why not simply tag it as 2.2.1?

To list the bookmarks you already made, enter

git tag -l

Creating a tag
Right after you found some nifty name for your tag – let’s say we call it 2.3 – create an annotated (not signed) tag with

git tag -a 2.3

Until here the tag will reside in your local repository only and will be pushed to your remote repos instantly if you command

git push --tags

You can switch back to any version you tagged using

git checkout 2.3

which is really helpful for both developers and users since you can distribute multiple versions in one repository.

Deleting a tag
If you simply want to delete a local tag, do

git tag -d v3.3.4

However, if you need to remove that tag from your remote github repository, you simply push nothing to the tag name.

git push origin :refs/tags/v3.3.4