# Copyright 2018 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
defmodule GoogleApi.Gax.Request do
@moduledoc """
This module is used to build an HTTP request
"""
@path_template_regex ~r/{(\+?[^}]+)}/i
defstruct method: :get, url: "", body: [], query: [], file: [], header: [], library_version: ""
@type param_location :: :body | :query | :header | :file
@type method :: :head | :get | :delete | :trace | :options | :post | :put | :patch
@type t :: %__MODULE__{
method: method(),
url: String.t(),
body: keyword(),
query: keyword(),
file: keyword(),
header: keyword(),
library_version: String.t()
}
@spec new() :: GoogleApi.Gax.Request.t()
def new do
%__MODULE__{}
end
@spec library_version(GoogleApi.Gax.Request.t()) :: {:ok, String.t()} | :error
def library_version(request), do: Map.fetch(request, :library_version)
@doc """
Specify the library version when building a request
## Parameters
* `request` (*type:* `GoogleApi.Gax.Request.t`) - Collected request options
* `version` (*type:* `String`) - Library version
## Returns
* `GoogleApi.Gax.Request.t`
"""
@spec library_version(GoogleApi.Gax.Request.t(), String.t()) :: GoogleApi.Gax.Request.t()
def library_version(request, version) do
%{request | library_version: version}
end
@spec method(GoogleApi.Gax.Request.t()) :: {:ok, atom()} | :error
def method(request), do: Map.fetch(request, :method)
@doc """
Specify the request method when building a request
## Parameters
* `request` (*type:* `GoogleApi.Gax.Request.t`) - Collected request options
* `m` (*type:* `String`) - Request method
## Returns
* `GoogleApi.Gax.Request.t`
"""
@spec method(GoogleApi.Gax.Request.t(), atom()) :: GoogleApi.Gax.Request.t()
def method(request, m) do
%{request | method: m}
end
@spec url(GoogleApi.Gax.Request.t()) :: {:ok, String.t()} | :error
def url(request), do: Map.fetch(request, :url)
@doc """
Specify the request URL when building a request
## Parameters
* `request` (*type:* `GoogleApi.Gax.Request.t`) - Collected request options
* `u` (*type:* `String`) - Request URL
## Returns
* `GoogleApi.Gax.Request.t`
"""
@spec url(GoogleApi.Gax.Request.t(), String.t(), map()) :: GoogleApi.Gax.Request.t()
def url(request, u, replacements) do
url(request, replace_path_template_vars(u, replacements))
end
def url(request, u) do
Map.put(request, :url, u)
end
defp replace_path_template_vars(u, replacements) do
Regex.replace(@path_template_regex, u, fn _, var -> replacement_value(var, replacements) end)
end
defp replacement_value("+" <> name, replacements) do
URI.decode(replacement_value(name, replacements))
end
defp replacement_value(name, replacements) do
replacements
|> Map.get(name, "")
|> to_string
end
@doc """
Add optional parameters to the request
## Parameters
* `request` (*type:* `GoogleApi.Gax.Request.t`) - Collected request options
* `definitions` (*type:* `Map`) - Map of parameter name to parameter location
* `options` (*type:* `keyword()`) - The provided optional parameters
## Returns
* `GoogleApi.Gax.Request.t`
"""
@spec add_optional_params(
GoogleApi.Gax.Request.t(),
%{optional(atom()) => param_location()},
keyword()
) :: GoogleApi.Gax.Request.t()
def add_optional_params(request, _, []), do: request
def add_optional_params(request, definitions, [{key, value} | tail]) do
case definitions do
%{^key => location} ->
request
|> add_param(location, key, value)
|> add_optional_params(definitions, tail)
_ ->
add_optional_params(request, definitions, tail)
end
end
@doc """
Add optional parameters to the request
## Parameters
* `request` (*type:* `GoogleApi.Gax.Request.t`) - Collected request options
* `location` (*type:* `atom()`) - Where to put the parameter
* `key` (*type:* `atom()`) - The name of the parameter
* `value` (*type:* `any()`) - The value of the parameter
## Returns
* `GoogleApi.Gax.Request.t`
"""
@spec add_param(GoogleApi.Gax.Request.t(), param_location(), atom(), any()) ::
GoogleApi.Gax.Request.t()
def add_param(request, :query, key, values) when is_list(values) do
Enum.reduce(values, request, fn value, req ->
add_param(req, :query, key, value)
end)
end
def add_param(request, location, key, value) do
Map.update!(request, location, &(&1 ++ [{key, value}]))
end
end