Simple Webmachine Extension (1/4): PUT

This post begins a four-part series that demonstrates how to take the simple os-environment Webmachine resource I wrote last week, and expand it to support modification, authorization, and conditional requests. Modification via PUT is up first.

I was in need of a break last night after flailing in the face of a new library-language-build-system for a few hours. So, I decided to hack some Webmachine (it was too late to sit down at the trap set).

I was thinking about how the os-environment resource from my last post could be extended. This post begins a four-part series in which new capabilities are added to env_resource.erl.


Let’s start with modification. Why not allow setting those variables?

I need to do three things: announce that the resource supports PUT, list what types of data it accepts, and then actually handle decoding the incoming data. Fifteen quick lines of code should handle it:

-export([allowed_methods/2, content_types_accepted/2, from_json/2]).

allowed_methods(RD, Ctx) ->
    {['GET', 'HEAD', 'PUT'], RD, Ctx}.

content_types_accepted(RD, Ctx) ->
    {[{"application/json", from_json}], RD, Ctx}.

from_json(RD, Ctx) ->
    case wrq:path_info(env, RD) of
        undefined ->
            {struct, MJ} = mochijson:decode(wrq:req_body(RD)),
            [ os:putenv(K, V) || {K, V} <- MJ ];
        Env ->
            MJ = mochijson:decode(wrq:req_body(RD)),
            os:putenv(Env, MJ)
    {true, RD, Ctx}.

Arbitrary decisions were made above:

  • Clients shall send JSON-encoded data. I could have just as easily added another element to the return value of content_types_accepted/2 and written another method to handle it (e.g. {"text/plain", from_text} and from_text/2). Accepting JSON is nice, since it makes PUT and GET simply symmetric.
  • /_env expects a JSON structure, while /_env/VARIABLE expects a string. Again with the simple symmetry between PUT and GET.
  • /_env only modifies or creates the variables described in the JSON structure it receives. Alternatively, it could have cleared out any unnamed environment variables, but this seemed unnecessary.
  • No body is returned in a successful response. It would have been fairly simple to generate the same body that would have been returned in a GET, then use wrq:append_to_response_body/2 to return a modified RD, but this also seemed unnecessary.

I can now set MY_VAR to "hello", using two different curl commands:

$ curl -X PUT -H "Content-type: application/json" \
   http://localhost:8000/_env -d "{\"MY_VAR\":\"hello\"}"

$ curl -X PUT -H "Content-type: application/json" \
   http://localhost:8000/_env/MY_VAR -d "\"hello\""

Come back tomorrow for part two, in which I’ll add authorization via username and password.
Update: part two is up.

Author: Bryan

I'm the creator of Symbology (, BeerRiot (, lots of homebrew, some furniture, and other things. There's more about me at

4 thoughts on “Simple Webmachine Extension (1/4): PUT”

  1. Ok, for a newbie how do you get this INTO a webmachine? Don’t you need a “.app” and supervisors and all that (like mywebdemo does)? Or is there a simpler command line that you use to start your server?

    If I patch your resource into “mywebdemo”, “wrq:path_info” always returns ‘undefined’. The Dispatch wiki page talks about “wrq:path_tokens”, “wrq:get_path_info”, and “wrq:disp_path”; but not “wrq:path_info”.

    I think your post assumes familiarity w/ webmachine and I am trying to use your example to gain that …. kind of a catch22 for me 😦

  2. Hey, Stranger. You’re right that my posts assume a little familiarity with Webmachine. I try to help with the learning curve by giving pointers to the appropriate docs, but I see that failed in this case, because the Dispatch wiki page was out of date. “:get_path_info” changed to just “:path_info” recently. Sorry about that – Justin has just updated the page.

    The reason that wrq:path_info/2 is returning ‘undefined’ for you, though, is likely that this dispatch line for env_resource looks different than the line for the default demo resource webmachine creates. If you go back to my previous post, you’ll see three lines of comments at the top of env_resource.erl. These are the dispatch lines you need (they tell Webmachine where to extract that ‘env’ token from).

    The dispatch for your webmachine instance is in mywebdemo_sup.erl (search for “Dispatch”). Add the two lines from my post to that Dispatch list, recompile, restart, and you’ll be set. Note that if you’ve copied the code from my examples into mywebdemo.erl, you’ll want to replace “env_resource” in my example dispatches with “mywebdemo” in yours.

    Warning to future readers: the last paragraph is incorrect if you downloaded Webmachine after this reply was written. Dispatch configuration is now handled in priv/dispatch.conf.

  3. Wow, thanks for the quick reply. I did finally notice the dispatch comment that I could copy to “mywebdemo_sup.erl” and got it all working. This is blowing my mind!:) I just LOVE the wmtrace facility and being able to see the Erlang evaluations. Wow, just wow. Now I need to think up a website to write in webmachine. 🙂

  4. Excellent – glad you’re up and running. Thanks for the feedback, and keep it coming – it’s fun learning the quirks one has internalized when new hands pick up a tool.

Leave a Reply to Wayfaring Stranger Cancel reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s