Current section
Files
Jump to
Current section
Files
lib/parser.ex
defmodule Frex.Parser do
@moduledoc """
Module for parsing the response of endpoint calls.
"""
@doc """
Parses a Freshbooks XML response (`xml_string`) and returns a map of its attributes.
Returns a tuple with `:ok` and a `Map` if the response is to a single item.
Returns a tuple with `:ok` and a `List` of `Map`s if the response is multiple item.
"""
def parse(xml_string) when is_bitstring(xml_string) do
[initial_response] = Quinn.parse(xml_string)
parse(initial_response)
end
def parse(%{attr: [_, status: "fail"], name: :response, value: [%{name: :error, value: [error_message]} | [%{name: :code, value: [error_code]} | _]]}) do
{:error,
%{status: "fail", message: error_message, code: error_code}}
end
def parse(%{attr: [_, status: "ok"], name: :response, value: [%{attr: _, name: _, value: []}]}) do
{:ok, []}
end
def parse(%{attr: [_, status: "ok"], value: [%{attr: page_info, value: response_data}]}) when length(page_info) > 0 do
{:ok, parse_response(response_data), clean_attrs(page_info)}
end
# Specific so that webhooks/reports don't get jumbled.
def parse(%{attr: [_, status: "ok"], value: [%{name: :callback_id, value: [value]}]}) do
{:ok,
%{callback_id: value}
|> Map.put(:status, "ok")}
end
def parse(%{attr: [_, status: "ok"], value: [%{value: response_data}]}) do
{:ok, parse_response(response_data)}
end
def parse(%{attr: [_, status: "ok"], value: []}) do
{:ok, %{status: "ok"}}
end
defp parse_response(response_data = [%{value: attrs} | _]) when length(attrs) > 1 do
response_data
|> clean_response_list
|> Enum.map(&put_attrs/1)
end
defp parse_response(response_data) do
response_data
|> put_attrs
|> Map.put(:status, "ok")
end
# Puts attributes from the Freshbooks API (`response`) response into a Map.
#
# Returns a `Map`.
defp put_attrs(response) do
Enum.reduce(response, %{}, fn(attr, acc) ->
Map.put(acc, attr.name, Enum.at(attr.value, 0))
end)
end
# Cleans up parsed XML with multiple attributes.
defp clean_response_list(response_list) do
Enum.map response_list, fn(item) ->
%{value: value} = item
value
end
end
defp clean_attrs(attrs) do
attr_map = Enum.map(attrs, fn({key, val}) ->
{key, String.to_integer(val)}
end)
attr_map |> Enum.into(%{})
end
end