Using Ewebmachine to create a link shortener (part 2)
Posted on October 03, 2014 by Clive in Elixir, eWebmachine
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: In this file, build the ShortenerLatestResource as follows: 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: 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 Add the following function: In order to service this, we also need to add in the following handle: 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 to With all this in place, fire it up: We can now put in some data points: Open a new terminal: To check the plain/text mimetype, type: and you should now see the text output of the handler. To check the application/json mimetype, type: 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.$ vim lib/shortener_latest_resource
defmodule ShortenerLatestResource do
use Ewebmachine
resource ['latest'] do
content_types_provided do
[
{'text/html', :to_html},
{'text/plain', :to_text},
{'application/json', :to_json}
]
end
to_html do
{:ok, template} = File.read('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)
end
to_text do
{:ok, latest_links} = ShortenUrlSrv.get_latest(20)
Enum.map(latest_links, fn ({code, link}) -> "#{base_url(_req)}#{code} #{link}\n" end )
end
to_json do
{:ok, latest_links} = ShortenUrlSrv.get_latest(20)
linklist = Enum.map(latest_links, fn ({code, link}) ->
shortlink = "#{base_url(_req)}#{code}"
{:struct, [{<<"short_link">>, <<"#{shortlink}">>}, {<<"long_link">>, <<"#{link}">>}]}
end)
"#{:mochijson2.encode({:struct, [{:latest, linklist}]})}\n"
end
defp base_url(req) do
host = :wrq.get_req_header("host", req)
"http://#{host}/"
end
end
end
<!DOCTYPE html>
<html>
<head>
<title>Latest Links</title>
</head>
<body>
<div class="navbar navbar-inverse">
<div class="navbar-inner">
<a class="brand" href="/">Shortener</a>
</div>
</div>
<div class="container">
<p>The latest shortened links are:
<ul>
{{#links}}
<li><a href="{{ short_link }}">{{ short_link }}</a> => <a href="{{ long_link }}">{{ long_link }}</a></li>
{{/links}}
</ul>
</p>
</div>
</body>
</html>
def put_url(url) do
GenServer.call(@server, {:put_url, url})
end
def get_latest(count) do
GenServer.call(@server, {:get_latest, count})
end
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 = Enum.map(ids, &(do_record_lookup(&1)))
{:reply, {:ok, result}, state}
end
defp do_record_lookup(id) do
record = case :ets.lookup(@tab, id) do
[] -> raise 'The id doesnt exist'
[record] -> record
end
record
end
supervisor(Ewebmachine.Sup,[[modules: [ShortenerShortenResource, ShortenerFetchResource],port: 18080]]),
supervisor(Ewebmachine.Sup,[[modules: [ShortenerLatestResource, ShortenerShortenResource, ShortenerFetchResource],port: 18080]]),
$ iex -S mix
iex > ShortenUrlSrv.put_url("http://www.distortedthinking.agency")
iex > ShortenUrlSrv.put_url("http://www.pragprog.com")
$ curl -i --header 'accept: text/plain' http://localhost:18080/latest
$ curl -i --header 'accept: application/json' http://localhost:18080/latest