Packages
mazurka
0.3.37
1.0.8
1.0.7
1.0.6
1.0.5
1.0.4
1.0.3
1.0.2
1.0.1
1.0.0
0.3.39
0.3.38
0.3.37
0.3.36
0.3.35
0.3.34
0.3.33
0.3.32
0.3.31
0.3.30
0.3.29
0.3.28
0.3.27
0.3.26
0.3.25
0.3.24
0.3.23
0.3.22
0.3.21
0.3.20
0.3.19
0.3.18
0.3.17
0.3.16
0.3.15
0.3.14
0.3.13
0.3.12
0.3.11
0.3.10
0.3.9
0.3.8
0.3.7
0.3.6
0.3.5
0.3.4
0.3.3
0.3.2
0.3.1
0.3.0
0.2.10
0.2.9
0.2.8
0.2.7
0.2.6
0.2.5
0.2.4
0.2.3
0.2.2
0.2.1
0.2.0
0.1.10
0.1.9
0.1.8
0.1.7
0.1.6
0.1.5
0.1.4
0.1.3
0.1.2
0.1.1
0.1.0
hypermedia api toolkit
Current section
Files
Jump to
Current section
Files
lib/mazurka/protocol/http/router.ex
defmodule Mazurka.Protocol.HTTP.Router do
@moduledoc """
A DSL for mazurka resources
"""
@doc false
defmacro __using__(opts) do
quote location: :keep do
import Mazurka.Protocol.HTTP.Router
@before_compile Mazurka.Protocol.HTTP.Router
use Mazurka.Protocol.HTTP.Request
use Plug.Builder, unquote(opts)
defp match(conn, _opts) do
case do_match(conn.method, conn.path_info) do
{:ok, resource, params, resource_params} when is_tuple(resource) ->
conn
|> Plug.Conn.put_private(:mazurka_route, elem(resource, 0))
|> Plug.Conn.put_private(:mazurka_resource, resource)
|> Plug.Conn.put_private(:mazurka_resource_params, resource_params)
|> Plug.Conn.put_private(:mazurka_params, params)
{:ok, resource, params, resource_params} ->
conn
|> Plug.Conn.put_private(:mazurka_route, resource)
|> Plug.Conn.put_private(:mazurka_resource, resource)
|> Plug.Conn.put_private(:mazurka_resource_params, resource_params)
|> Plug.Conn.put_private(:mazurka_params, params)
end
end
def resolve(mod) do
resolve(mod, %{})
end
defp dispatch(%Plug.Conn{private: %{mazurka_route: route}} = conn, _opts) do
Mazurka.Protocol.HTTP.Router.Handler.__handle__(conn, route)
end
defoverridable [match: 2, dispatch: 2]
end
end
@doc false
defmacro __before_compile__(_) do
quote do
import Mazurka.Protocol.HTTP.Router, only: []
def resolve(_, _) do
{:error, :not_found}
end
def resolve_module(_) do
nil
end
def params(_) do
{:error, :not_found}
end
defp do_resolve(method, params, resource_params) do
has_values = Enum.all?(params, fn
(nil) -> false
(:undefined) -> false
(_) -> true
end)
if has_values do
{:ok, method, params, resource_params}
else
{:error, :not_found}
end
end
end
end
@doc """
Main API to define routes.
It accepts an expression representing the path and many options
allowing the match to be configured.
## Examples
match "/foo/bar", Api.Resource.Foo.Bar
"""
defmacro match(path, resource, resource_params \\ {:%{}, [], []}) do
compile(nil, path, resource, resource_params)
end
for method <- [:get, :post, :put, :patch, :delete, :options, :head] do
@doc """
Dispatches to the path only if the request is a #{Plug.Router.Utils.normalize_method(method)} request.
See `match/3` for more examples.
"""
defmacro unquote(method)(path, resource, resource_params \\ {:%{}, [], []}) do
compile(unquote(method), path, resource, resource_params)
end
end
@doc false
def __route__(method, path) do
method = method && Plug.Router.Utils.normalize_method(method) || quote(do: _)
{vars, match} = Plug.Router.Utils.build_path_match(path)
{params, map_params, list_params} = format_params(vars)
{method, match, params, {:%{}, [], map_params}, list_params}
end
@doc false
def __resolve__(method, path) do
{format_method(method),
format_path(path)}
end
defp format_method({:_, _, _}), do: "GET"
defp format_method(method), do: method
defp format_path({:_path, _, _}), do: []
defp format_path(path), do: path
defp format_params(vars) do
vars
|> Enum.reverse()
|> Enum.reduce({[], [], []}, fn(var, {params, map_params, list_params}) ->
v = {var, [], nil}
{[to_string(var) | params], [{to_string(var), v} | map_params], [v | list_params]}
end)
end
defp compile(method, path, resource, resource_params) when is_list(resource_params) do
compile(method, path, resource, {:%{}, [], resource_params})
end
defp compile(method, {:_, _, _}, resource, resource_params) do
compile(method, "/*_path", resource, resource_params)
end
defp compile(method, path, resource, resource_params) do
[
quote bind_quoted: [method: method,
path: path,
resource: resource,
resource_params_expr: resource_params] do
resource_params = Macro.escape(resource_params_expr)
{method, match, params, map_params, list_params} = Mazurka.Protocol.HTTP.Router.__route__(method, path)
defp do_match(unquote(method), unquote(match)) do
{:ok, unquote(resource), unquote(map_params), unquote(resource_params)}
end
{resolve_method, resolve_match} = Mazurka.Protocol.HTTP.Router.__resolve__(method, match)
def resolve(unquote(resource), unquote(map_params)) do
do_resolve(unquote(resolve_method), unquote(resolve_match), unquote(resource_params))
end
def resolve(unquote(resource), unquote(list_params)) do
do_resolve(unquote(resolve_method), unquote(resolve_match), unquote(resource_params))
end
arroba_path = String.replace(path, ":", "@")
def resolve_module(unquote(resource)) do
unquote(resource)
end
if is_binary(method) do
def resolve_module(unquote(method <> " " <> arroba_path)) do
unquote(resource)
end
if method == "GET" do
def resolve_module(unquote(arroba_path)) do
unquote(resource)
end
end
end
def params(unquote(resource)) do
{:ok, unquote(params), unquote(resource_params)}
end
end,
Mazurka.Protocol.HTTP.Router.Tests.register_tests(resource)
]
end
end