Skip to content

Instantly share code, notes, and snippets.

@aoswalt
Last active June 20, 2018 15:33
Show Gist options
  • Save aoswalt/599b324398167e7b6bfe0c6a175ff5cc to your computer and use it in GitHub Desktop.
Save aoswalt/599b324398167e7b6bfe0c6a175ff5cc to your computer and use it in GitHub Desktop.
soap method macro for building request body and handling soap responses
defmodule MdToolbox.Api.SoapMethod do
alias __MODULE__
alias MdToolbox.Api.Request
@doc "Builds the request from params"
@callback build_request(params :: list()) :: map()
@doc "Parses the request's response into data"
@callback parse_response(request :: Request.t()) :: Request.t()
@doc "Updates the request with the method data"
@callback set_request_data(request :: Request.t()) :: Request.t()
defmacro __using__(opts) do
if opts[:result_struct] == nil do
raise ArgumentError, messge: ":result_struct must be a module or false"
end
quote do
@behaviour Method
@bare_mod_name __MODULE__ |> Atom.to_string() |> String.split(".") |> Enum.reverse() |> hd
Module.put_attribute(
__MODULE__,
:method_name,
unquote(opts[:method_name]) || @bare_mod_name
)
Module.put_attribute(
__MODULE__,
:response_key,
unquote(opts[:response_key]) ||
@bare_mod_name |> Kernel.<>("Response") |> String.to_atom()
)
Module.put_attribute(
__MODULE__,
:result_key,
unquote(opts[:result_key]) || @bare_mod_name |> Kernel.<>("Result") |> String.to_atom()
)
Module.put_attribute(__MODULE__, :result_struct, unquote(opts[:result_struct]))
Module.put_attribute(
__MODULE__,
:data_set_key,
unquote(opts[:data_set_key]) || :NewDataSet
)
@impl true
def parse_response(%Request{response: response} = request) do
data =
response
|> Map.get(@response_key)
|> from_soap(@result_key)
|> convert_map_or_list(@result_struct)
%Request{request | data: data}
end
defp from_soap(nil, key), do: nil
defp from_soap(data, key) do
case data do
%{^key => _} ->
data
|> Kernel.get_in([@result_key, :"diffgr:diffgram", @data_set_key])
|> new_data_to_list()
_ ->
data
end
end
defp new_data_to_list(nil), do: []
defp new_data_to_list(data), do: Enum.map(data, &elem(&1, 1))
defp convert_map_or_list(%{} = data, struct_name), do: Soapy.from_soap(data, struct_name)
defp convert_map_or_list(data, struct_name) when is_list(data) do
Enum.map(data, fn d -> Soapy.from_soap(d, struct_name) end)
end
@impl true
def set_request_data(%Request{} = request) do
request
|> Request.set_method_module(__MODULE__)
|> Request.set_method_name(@method_name)
end
defoverridable Method
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment