Packages
maru
0.13.0
0.14.0-pre.1
0.13.2
0.13.1
0.13.0
0.12.5
0.12.4
0.12.3
0.12.2
0.12.1
0.12.0
0.11.5
0.11.4
0.11.3
0.11.2
0.11.1
0.11.0
0.10.6
0.10.5
0.10.4
0.10.3
0.10.2
0.10.1
0.10.0
0.9.6
0.9.5
0.9.4
0.9.3
0.9.2
0.9.1
0.9.0
0.8.5
0.8.4
0.8.3
0.8.2
0.8.1
0.8.0
0.7.2
0.7.1
0.7.0
0.6.0
0.5.1
0.5.0
0.4.1
0.4.0
0.3.1
0.3.0
0.2.10
0.2.9
0.2.8
0.2.7
0.2.6
0.2.5
REST-like API micro-framework for elixir inspired by grape.
Current section
Files
Jump to
Current section
Files
lib/maru/resource/helper.ex
alias Maru.Resource
defmodule Resource.Helper do
alias Resource.MaruPlug
def set_version(version, %Macro.Env{module: module}) do
resource = Module.get_attribute(module, :resource)
new_resource = %{resource | version: version}
Module.put_attribute(module, :resource, new_resource)
end
def push_path(path, %Macro.Env{module: module}) when is_list(path) do
%{path: orig_path} = resource = Module.get_attribute(module, :resource)
new_resource = %{
resource
| path: orig_path ++ path
}
Module.put_attribute(module, :resource, new_resource)
end
def push_plug(plug, %Macro.Env{module: module}) do
%{plugs: plugs} = resource = Module.get_attribute(module, :resource)
new_resource = %{
resource
| plugs: MaruPlug.merge(plugs, plug)
}
Module.put_attribute(module, :resource, new_resource)
end
@doc "merge mounted routes to current scope."
def mount(mounted_module, %Macro.Env{module: module} = env) do
resource = Module.get_attribute(module, :resource)
Enum.each(mounted_module.__routes__(), fn mounted_route ->
if not is_nil(resource.version) and not is_nil(mounted_route.version) do
raise "can't mount a versional router to another versional router"
end
versioning_path = (is_nil(resource.version) && []) || [{:version}]
mounted =
%{
mounted_route
| version: mounted_route.version || resource.version,
path: versioning_path ++ resource.path ++ mounted_route.path,
parameters: resource.parameters ++ mounted_route.parameters
}
|> Maru.Builder.Pipeline.after_mount(mounted_module, env)
|> Maru.Builder.Exception.after_mount(mounted_module, env)
Module.put_attribute(module, :mounted, mounted)
end)
end
@doc """
Generate endpoint called within route block.
"""
def dispatch(ep) do
conn =
if ep.has_params do
quote do
%Plug.Conn{
private: %{
maru_params: var!(params)
}
} = var!(conn)
end
else
quote do: var!(conn)
end
quote do
def endpoint(unquote(conn), unquote(ep.func_id)) do
unquote(ep.block)
end
end
end
def endpoint(ep, %Macro.Env{module: module} = env) do
resource = Module.get_attribute(module, :resource)
version = (is_nil(resource.version) && []) || [{:version}]
func_id = make_func_id(ep.method, resource.version, resource.path ++ ep.path)
method_context = %{
block: ep.block,
method: ep.method,
version: resource.version,
path: version ++ resource.path ++ ep.path,
helpers: resource.helpers,
plugs: MaruPlug.merge(resource.plugs, MaruPlug.pop(env)),
func_id: func_id
}
Module.put_attribute(module, :method_context, method_context)
router =
method_context
|> Map.take([:method, :version, :path, :helpers, :plugs])
|> Map.merge(%{module: module, func_id: func_id})
Module.put_attribute(module, :router, struct(Maru.Router, router))
Maru.Builder.Parameter.before_parse_router(env)
Maru.Builder.Description.before_parse_router(env)
router = Module.get_attribute(module, :router)
Module.put_attribute(module, :routes, router)
endpoint =
Module.get_attribute(module, :method_context)
|> Map.take([:block, :func_id])
|> Map.put(:has_params, [] != router.parameters)
Module.put_attribute(module, :endpoints, struct(Maru.Resource.Endpoint, endpoint))
end
defp make_func_id(method, version, path) do
method = method |> to_string |> String.upcase()
version = (is_nil(version) && "_") || version
path =
path
|> Enum.map(fn
atom when is_atom(atom) -> ":#{atom}"
string when is_binary(string) -> string
end)
|> Enum.join("/")
:"#{version}.#{method}.#{path}"
end
end