defmodule Pivo.Endpoint do @moduledoc """ Endpoint behaviour module. Sets the endpoint configuration. This module is meant to be `use`'d in custom modules in order to support different endpoints of the Pivotal's Tracker API. Receives a `params` keyword list with the following keys: - Required + `path` - String + `http_methods` - list of triplets {action_verb, context, params} - Optional + `path_params` - keyword list ## Example defmodule Pivo.MeEndpoint do use Pivo.Endpoint, path: "/me", http_methods: [ {:get, [resource: Me], []} ] end """ @type t :: module() @typep params :: Keyword.t() @doc """ Returns the current endpoint `path`. """ @callback path() :: String.t() @doc """ Returns the current endpoint `path_params`. """ @callback path_params() :: params() defmacro __using__(options) do path = Keyword.get(options, :path, "/") path_params = Keyword.get(options, :path_params, []) http_methods = Keyword.get(options, :http_methods, []) quote bind_quoted: [ path: path, path_params: path_params, http_methods: http_methods ], location: :keep do @behaviour Pivo.Endpoint @impl true def path, do: unquote(path) @impl true def path_params, do: unquote(path_params) end end @doc """ Builds the `url_path` for a given `Pivo.Endpoint` using the provided parameters. """ def build_path_with_params(endpoint, path_params) do string_path_params = stringify_path_params(endpoint.path_params(), path_params) Enum.reduce(string_path_params, endpoint.path(), fn {param_key, param_string_value}, url -> String.replace(url, ~r/({#{Atom.to_string(param_key)}})/, param_string_value) end) end defp stringify_path_params(params_def, params_val) do for {param_key, param_type} <- params_def do case Keyword.fetch(params_val, param_key) do {:ok, value} -> {param_key, path_param_to_string(param_type, value)} :error -> raise ArgumentError, message: "invalid argument path_params, missing required parameter: #{param_key}" end end end defp path_param_to_string(:integer, value) when is_integer(value) do Integer.to_string(value) end defp path_param_to_string(_, value) do to_string(value) end end