Current section
Files
Jump to
Current section
Files
lib/correios/cep/parser.ex
defmodule Correios.CEP.Parser do
@moduledoc """
Parser for Correios API responses.
"""
import SweetXml, only: [sigil_x: 2, xpath: 2, xpath: 3]
alias Correios.CEP.{Address, Error}
@address_map [
street: "end",
complement: "complemento",
complement2: "complemento2",
neighborhood: "bairro",
city: "cidade",
state: "uf",
postal_code: "cep"
]
@xmap_params for {new_key, old_key} <- @address_map,
into: [],
do: {new_key, ~x"./#{old_key}/text()"}
@doc """
Parses a successful Correios API response body to `#{inspect(Address)}` struct.
When the response body is empty, returns a not found `#{inspect(Error)}` struct.
## Examples
iex> #{inspect(__MODULE__)}.parse_ok(response_body)
%#{inspect(Address)}{ ... }
iex> #{inspect(__MODULE__)}.parse_ok(response_body)
%#{inspect(Error)}{
type: :postal_code_not_found,
message: "Postal code not found",
reason: "CEP NAO ENCONTRADO"
}
"""
@spec parse_ok(String.t()) :: Address.t() | Error.t()
def parse_ok(response) when is_binary(response) do
response
|> xpath(~x"//return"o, @xmap_params)
|> build_response()
end
@spec build_response(map() | nil) :: Address.t() | Error.t()
defp build_response(nil),
do: Error.new(:postal_code_not_found, "Postal code not found", "Empty response")
defp build_response(response) when is_map(response), do: Address.new(response)
@doc """
Parses a Correios API response error to `#{inspect(Error)}` struct.
## Examples
iex> #{inspect(__MODULE__)}.parse_error(response_body)
%#{inspect(Error)}{ ... }
iex> #{inspect(__MODULE__)}.parse_error(:timeout)
%#{inspect(Error)}{
type: :request_error,
message: "Request error",
reason: "timeout"
}
"""
@spec parse_error(any()) :: Error.t()
def parse_error(response) when is_binary(response) do
response
|> xpath(~x"//faultstring/text()")
|> build_error()
end
def parse_error(response), do: Error.new(:request_error, "Request error", response)
@spec build_error(charlist()) :: Error.t()
defp build_error('CEP NAO ENCONTRADO' = reason),
do: Error.new(:postal_code_not_found, "Postal code not found", reason)
defp build_error(reason), do: Error.new(:unknown, "Unknown error", reason)
end