Current section
Files
Jump to
Current section
Files
lib/docusign/request_builder.ex
# NOTE: This file is auto generated by OpenAPI Generator
# https://openapi-generator.tech
# Do not edit this file manually.
defmodule DocuSign.RequestBuilder do
@moduledoc """
Helper functions for building Req requests
"""
@doc """
Specify the request `method` when building a request.
Does not override the `method` if one has already been specified.
### Parameters
- `request` (Map) - Collected request options
- `method` (atom) - Request method
### Returns
Map
"""
@spec method(map(), atom()) :: map()
def method(request, method) do
Map.put_new(request, :method, method)
end
@doc """
Specify the request `url` when building a request.
Does not override the `url` if one has already been specified.
### Parameters
- `request` (Map) - Collected request options
- `url` (String) - Request URL
### Returns
Map
"""
@spec url(map(), String.t()) :: map()
def url(request, url) do
Map.put_new(request, :url, url)
end
@doc """
Add optional parameters to a request
### Parameters
- `request` (Map) - Collected request options
- `definitions` (Map) - Map of parameter name to parameter location.
- `options` (KeywordList) - The provided optional parameters
### Special Parameters
- `:headers` - A map of custom headers to add to the request. These will be merged
with the default headers. This is useful for DocuSign-specific headers like
`X-DocuSign-Edit` which are required for certain operations on locked envelopes.
### Returns
Map
### Examples
# Add custom headers for locked envelope operations
optional_params = %{body: :body}
opts = [
body: envelope_data,
headers: %{"X-DocuSign-Edit" => ~s({"LockToken": "abc123", "LockDurationInSeconds": "600"})}
]
add_optional_params(request, optional_params, opts)
"""
@spec add_optional_params(map(), %{optional(atom()) => atom()}, keyword()) :: map()
def add_optional_params(request, _, []), do: request
def add_optional_params(request, definitions, [{:headers, custom_headers} | tail]) when is_map(custom_headers) do
# Handle custom headers specially - merge them with existing headers
request =
Enum.reduce(custom_headers, request, fn {key, value}, acc ->
add_param(acc, :headers, key, value)
end)
add_optional_params(request, definitions, tail)
end
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 non-optional parameters to a request
### Parameters
- `request` (Map) - Collected request options
- `location` (atom) - Where to put the parameter
- `key` (atom) - The name of the parameter
- `value` (any) - The value of the parameter
### Returns
Map
"""
@spec add_param(map(), atom(), atom(), any()) :: map()
def add_param(request, :body, :body, value) do
# Models now handle nil stripping via custom Jason.Encoder
Map.put(request, :body, Jason.encode!(value))
end
def add_param(request, :body, key, value) do
request
|> Map.put_new(:form_multipart, [])
|> Map.update!(:form_multipart, fn parts ->
parts ++ [{to_string(key), Jason.encode!(value), content_type: "application/json"}]
end)
end
def add_param(request, :headers, key, value) do
headers = Map.get(request, :headers, [])
Map.put(request, :headers, [{key, value} | headers])
end
def add_param(request, :query, key, value) do
query_params = Map.get(request, :params, [])
Map.put(request, :params, [{key, value} | query_params])
end
def add_param(request, :file, key, value) do
request
|> Map.put_new(:form_multipart, [])
|> Map.update!(:form_multipart, fn parts ->
parts ++ [{to_string(key), File.read!(value)}]
end)
end
def add_param(request, :form, key, value) do
request
|> Map.put_new(:form_multipart, [])
|> Map.update!(:form_multipart, fn parts ->
parts ++ [{to_string(key), value}]
end)
end
@doc """
Handle the response for a Req request.
### Parameters
- `response` (Req.Response.t) - The response object
### Returns
{:ok, any()} on success
{:error, Req.Response.t} on failure
"""
@spec evaluate_response({:ok, Req.Response.t()} | {:error, any()}, list({integer(), any()})) ::
{:ok, any()} | {:error, Req.Response.t()}
def evaluate_response({:ok, %Req.Response{status: status} = response}, mapping) do
case Enum.find(mapping, fn {code, _} -> code == status end) do
{_, nil} ->
{:ok, nil}
{_, false} ->
# Special case for endpoints that return raw data
{:ok, response.body}
{_, decoder} when is_function(decoder) ->
decoder.(response.body)
{_, module} when is_atom(module) ->
# Handle module names (like EnvelopeSummary)
# Convert string keys to atoms and decode with module's decode function
atomized = atomize_keys(response.body)
{:ok, module.decode(atomized)}
nil ->
{:error, response}
end
end
def evaluate_response({:error, _reason} = error, _mapping), do: error
defp atomize_keys(map) when is_map(map) do
Map.new(map, fn {k, v} ->
{String.to_existing_atom(k), atomize_keys(v)}
end)
rescue
ArgumentError ->
# If atom doesn't exist, fall back to creating it (careful with memory)
Map.new(map, fn {k, v} ->
{String.to_atom(k), atomize_keys(v)}
end)
end
defp atomize_keys(list) when is_list(list) do
Enum.map(list, &atomize_keys/1)
end
defp atomize_keys(value), do: value
@doc """
This function ensures that the `body` parameter is always set.
This handles cases where POST, PATCH and PUT requests require a body
even when it's empty.
### Parameters
- `request` (Map) - Collected request options
### Returns
Map
"""
@spec ensure_body(map()) :: map()
def ensure_body(request) do
case Map.get(request, :body) do
nil -> Map.put(request, :body, Jason.encode!(%{}))
_ -> request
end
end
end