defmodule NDCEx do require HTTPoison require NDCLogger use Timex def request(method, data, config) do request_start_time = Time.now NDCEx.Message.Base.build_document(method, data, config) |> rest_call_with_message(method, data, config, request_start_time) end def rest_call_with_message({:ok, request_xml}, method, data, config, request_start_time) do url = NDCEx.Message.Base.build_url(config[:server][:url], method) headers = get_headers(config[:rest][:headers], method) #processing_end = Time.now #TODO Handle different exceptions during request and return different errors # try do case HTTPoison.post(url, request_xml, headers, is_ssl(config[:ssl], config[:label])) do {:ok, %HTTPoison.Response{body: response_xml, headers: headers, status_code: 200 }} -> decode_response(response_xml, headers) |> NDCNormalize.remove_soap_header(config[:soap][:soap_header]) |> NDCNormalize.remove_soap_tags(config[:soap][:response_namespace_tags]) |> NDCNormalize.remove_namespace(config[:soap][:response_namespace]) |> NDCNormalize.remove_message_wrapper(config[:message]) |> NDCNormalize.check_ndc_errors() ## This function returns a tuple including the xml and the atom :error or :ok depending if there are any error on the response or not. |> process_response(method, request_xml, data, config, request_start_time) {:ok, %HTTPoison.Response{body: response_xml, headers: _headers, status_code: _status_code }} -> process_response({:error, NDCNormalize.remove_soap_tags(response_xml, config[:soap][:response_namespace])}, method, request_xml, data, config, request_start_time) {:error, %HTTPoison.Error{id: id, reason: reason}}-> process_response({:error, "Error. Reason of error: #{to_string(reason)}"}, method, request_xml, data, config, request_start_time) #{:ok, %HTTPoison.Response{status_code: 404}} -> #{:error, error_message("NDC host/URL invalid or missing")} {:error, reason} -> IO.inspect reason {:error, reason} reason -> IO.inspect reason {:error, error_message("Unknown HTTP response error")} end # catch _ , _ -> # {:error, error_message("Exception while HTTP request")} # end end defp build_url(url, method), do: String.replace(url, "{{NDC-method}}", Atom.to_string(method)) defp error_message(message), do: "#{message}" defp remove_tag(doc, tag), do: String.replace(doc, tag, "") def get_mix_config(key) when is_atom(key), do: Application.get_env(:ndc_ex_sdk, key) defp get_headers(headers, method) do Enum.map(headers, fn ({key, value}) -> {key, String.replace(value, "{{NDC-method}}", Atom.to_string(method))} end) end defp process_response({status, response}, method, request, data, config, request_start_time) do response_time = Time.diff(Time.now, request_start_time, :milliseconds) request_xml = request response_xml = "\n\n\n#{response}" NDCLogger.event(config[:label], method, data, request_xml, response_xml) {status, response_xml} end defp is_ssl(config, _) when config == nil, do: [timeout: 60000, recv_timeout: 60000] defp is_ssl(ssl_config, provider) when ssl_config != nil do dir = "ndc_providers/#{String.downcase(provider)}/" path = if File.exists?(Path.expand(File.cwd! <> "../../../config/#{dir}/#{ssl_config[:certfile]}")) do Path.expand(File.cwd! <> "../../../config/#{dir}") else "test/#{dir}" end [ hackney: [ # :hackney options ssl_options: [ # :ssl options cacertfile: path <> ssl_config[:cacertfile], # CA certificate used to validate server cert; path(), "string" is ok certfile: path <> ssl_config[:certfile], # client certificate, signed by CA; path(), "string" is ok keyfile: path <> ssl_config[:keyfile], # private key for client.crt; path(). "string" is ok password: ssl_config[:password] # password for keyfile; string(), "string" not ok, use 'char list' ] ], timeout: 60000, recv_timeout: 60000 ] end defp decode_response(body, headers) do gzipped = Enum.any?(headers, fn (kv) -> case kv do {"Content-Encoding", "gzip"} -> true _ -> false end end) # body is an Elixir string if gzipped do :zlib.gunzip(body) else body end end end