Playing With Fire

Exploring the web one Elixir at a time

Using Ewebmachine to create a link shortener (part 2)

In the last part of this series Using Ewebmachine to create a link shortener (part 1) we covered setting up the basic application and services.

In this part, we will add in some listing functionality, that will output in a number of formats: HTML, XML, JSON.

So, first things first, lets set about getting list of the available URL mappings.

In the Shortener application, create a new resource file:

$ vim lib/shortener_latest_resource

In this file, build the ShortenerLatestResource as follows:

defmodule ShortenerLatestResource do
  use Ewebmachine

  resource ['latest'] do

    content_types_provided do
        {'text/html', :to_html},
        {'text/plain', :to_text},
        {'application/json', :to_json}

    to_html do
      {:ok, template} ='templates/latest_resource.html.mustache')

      host = base_url(_req)
      {:ok, latest_links} = ShortenUrlSrv.get_latest(20)
      ctx = [links: for {short, long} <- latest_links do [short_link: "#{host}#{short}", long_link: long] end ]
      Mustache.render(template, ctx)

    to_text do
      {:ok, latest_links} = ShortenUrlSrv.get_latest(20), fn ({code, link}) -> "#{base_url(_req)}#{code} #{link}\n" end )

    to_json do
      {:ok, latest_links} = ShortenUrlSrv.get_latest(20)
      linklist =, fn ({code, link}) ->
        shortlink = "#{base_url(_req)}#{code}"
    {:struct, [{<<"short_link">>, <<"#{shortlink}">>}, {<<"long_link">>, <<"#{link}">>}]}
      "#{:mochijson2.encode({:struct, [{:latest, linklist}]})}\n"

    defp base_url(req) do
      host = :wrq.get_req_header("host", req)

As you might be able to tell, there are couple of things missing that we need to provide in order to get this to work.

The first is the template: latest_resource.html.mustache, and then the ShortenerUrlSrv.get_latest/1 function.

Lets address the template first.

Create the templates/latest_resource.html.mustache and add the following to it:

&lt;!DOCTYPE html&gt;
    &lt;title&gt;Latest Links&lt;/title&gt;
    &lt;div class="navbar navbar-inverse"&gt;
      &lt;div class="navbar-inner"&gt;
        &lt;a class="brand" href="/"&gt;Shortener&lt;/a&gt;
    &lt;div class="container"&gt;
      &lt;p&gt;The latest shortened links are:
          &lt;li&gt;&lt;a href="{{ short_link }}"&gt;{{ short_link }}&lt;/a&gt; =&gt; &lt;a href="{{ long_link }}"&gt;{{ long_link }}&lt;/a&gt;&lt;/li&gt;

As you might tell, if you read both Basic Templating with Elixir-Mustache and Using a template file with Elixir and Ewebmachine<a href=”/“ title=>, we are using some of the lessons from there.

Next, we need to add the functionality to get the data our of our datastore.

In the lib/shortener_url_srv.ex file, under

  def put_url(url) do, {:put_url, url})

Add the following function:

  def get_latest(count) do, {:get_latest, count})

In order to service this, we also need to add in the following handle:

  def handle_call({:get_latest, count}, _from, %St{next: n} = state) do
    start = n - 1
    last = max(n - count, 0)
    ids = for item <- last .. start, do: b36_encode(item)

    result =, &(do_record_lookup(&1)))
    {:reply, {:ok, result}, state}

  defp do_record_lookup(id) do
    record = case :ets.lookup(@tab, id) do
      [] -> raise 'The id doesnt exist'
      [record] -> record

The last thing that we need to do is add the resource to the list in the Supervisor:

Open lib/shortener_supervisor.ex and change from

  supervisor(Ewebmachine.Sup,[[modules: [ShortenerShortenResource, ShortenerFetchResource],port: 18080]]),


  supervisor(Ewebmachine.Sup,[[modules: [ShortenerLatestResource, ShortenerShortenResource, ShortenerFetchResource],port: 18080]]),

With all this in place, fire it up:

  $ iex -S mix

We can now put in some data points:

  iex > ShortenUrlSrv.put_url("")
  iex > ShortenUrlSrv.put_url("")

Open a new terminal:

To check the plain/text mimetype, type:

  $ curl -i --header 'accept: text/plain' http://localhost:18080/latest

and you should now see the text output of the handler.

To check the application/json mimetype, type:

  $ curl -i --header 'accept: application/json' http://localhost:18080/latest

There should now be json output to the screen.

Finally, in your browser go to http://localhost:18080/latest and you should see the entries in a list on the page.