Skip to content

Instantly share code, notes, and snippets.

@mworrell
Last active May 5, 2022 07:53
Show Gist options
  • Select an option

  • Save mworrell/08a9f2115c2df7a3f3068b500564314d to your computer and use it in GitHub Desktop.

Select an option

Save mworrell/08a9f2115c2df7a3f3068b500564314d to your computer and use it in GitHub Desktop.
Zotonic 1.0 - Template model for the OMDB movie database - source code to accompany the documentation
-module(m_omdb).
-behaviour(zotonic_model).
-export([
m_get/3
]).
-include_lib("zotonic_core/include/zotonic.hrl").
-define(API_URL, "http://www.omdbapi.com/?").
-spec m_get(Keys, Msg, Context) -> Return when
Keys :: list(),
Msg :: zotonic_model:opt_msg(),
Return :: zotonic_model:return(),
Context:: z:context().
% Syntax: m.omdb.api_url
m_get([ <<"api_url">> | Rest ], _Msg, _Context) ->
{ok, {z_convert:to_binary(?API_URL), Rest}};
% Syntax: m.omdb["tt0123456789"]
m_get([ <<"tt", _/binary>> = Id | Rest ], _Msg, _Context) ->
{ok, {fetch_data([ {id, Id} ]), Rest}};
% Syntax: m.omdb["some title"]
m_get([ Title | Rest ], _Msg, _Context) when is_binary(Title) ->
{ok, {fetch_data([ {id, Id} ]), Rest}};
% Syntax: m.omdb.sometype["tt0123456789"]
m_get([ Type, <<"tt", _/binary>> = Id | Rest ], _Msg, _Context)
when Type =:= <<"movies">>;
Type =:= <<"series">>;
Type =:= <<"episode">> ->
{ok, {fetch_data([ {type, Type}, {id, Id} ]), _Msg, Rest}};
% Syntax: m.omdb.sometype[QueryString]
m_get([ Type, QueryString | Rest ], _Msg, _Context)
when Type =:= <<"movies">>;
Type =:= <<"series">>;
Type =:= <<"episode">> ->
{ok, {fetch_data([ {type, Type}, {title, QueryString} ]), Rest}};
% Syntax: m.omdb[{query QueryParams}]
% For m.omdb[{query title="Dollhouse"}], Query is: [{title,"Dollhouse"}]
m_get([ {query, Query} | Rest ], _Msg, _Context) ->
{ok {fetch_data(Query), Rest}};
% Syntax: m.omdb.sometype[{query QueryParams}]
% For m.omdb.series[{query title="Dollhouse"}], Query is: [{title,"Dollhouse"}] and Q is: [{type,"series"}]
m_get([ Type, {query, Query} | Rest ], _Msg, _Context)
when Type =:= <<"movies">>;
Type =:= <<"series">>;
Type =:= <<"episode">> ->
{ok, {fetch_data([ {type, Type} | Query ]), Rest}}.
-spec fetch_data(Query) -> list() when Query:: list().
fetch_data([]) ->
[{error, "Params missing"}];
fetch_data(Query) ->
case proplists:is_defined(title, Query) or proplists:is_defined(id, Query) of
false -> [{error, "Param id or title missing"}];
true ->
QueryParts = lists:map(fun(Q) ->
make_query_string(Q)
end, Query),
Url = ?API_URL ++ string:join(QueryParts, "&"),
case get_page_body(Url) of
{error, Error} ->
[{error, Error}];
Json ->
{struct, JsonData} = mochijson2:decode(Json),
lists:map(fun(D) ->
convert_data_prop(D)
end, JsonData)
end
end.
%% Translate query params id, title and type into parameters that OMDB wants
-spec make_query_string({Key, Value}) -> string() when
Key:: atom(),
Value:: binary() | string() | atom().
make_query_string({id, Id}) ->
"i=" ++ z_url:url_encode(Id);
make_query_string({title, Title}) ->
"t=" ++ z_url:url_encode(Title);
make_query_string({type, Type}) ->
"type=" ++ z_url:url_encode(Type);
make_query_string(_) ->
"".
%% Translate binary keys to atoms
-spec convert_data_prop({Key, Value}) -> {atom(), string()} when
Key:: binary(),
Value:: binary().
convert_data_prop({Key, Value}) ->
{z_convert:to_atom(string:to_lower(z_convert:to_list(Key))), Value}.
get_page_body(Url) ->
case httpc:request(get, {Url, []}, [], []) of
{ok, {_, Headers, Body}} ->
case content_length(Headers) of
0 -> {error, "No content"};
_ -> Body
end;
Error ->
{error, Error}
end.
content_length(Headers) ->
list_to_integer(proplists:get_value("content-length", Headers, "0")).
@williamthome

Copy link
Copy Markdown

@mworrell

mworrell commented May 5, 2022

Copy link
Copy Markdown
Author

@williamthome Thanks!

@mworrell

mworrell commented May 5, 2022

Copy link
Copy Markdown
Author

@williamthome Ok if I copy your version over to this gist?

@williamthome

Copy link
Copy Markdown

@williamthome Ok if I copy your version over to this gist?

Of course! o/

@mworrell

mworrell commented May 5, 2022

Copy link
Copy Markdown
Author

Thanks, copied it!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment