Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Null object cannot be converted to a value type #23

Closed
frahugo opened this issue Jun 9, 2021 · 1 comment
Closed

Null object cannot be converted to a value type #23

frahugo opened this issue Jun 9, 2021 · 1 comment

Comments

@frahugo
Copy link
Contributor

frahugo commented Jun 9, 2021

I want to use the API to assign values to recipient tabs in an envelope. So I use something like this:

DocuSign.Api.EnvelopeRecipientTabs.recipients_put_recipient_tabs(connection, account_id, envelope_id, "1", EnvelopeRecipientTabs: newtabs)

newtabs was built using the values returned from DocuSign.Api.EnvelopeRecipientTabs.recipients_get_recipient_tabs/4. Some fields are nil.

When Poison encodes the model, nil value get serialized to null and the DocuSign API does not like it. It returns this error:

   body: "{\r\n  \"errorCode\": \"INVALID_REQUEST_BODY\",\r\n  \"message\": \"The request body is missing or improperly formatted. Null object cannot be converted to a value type.\"\r\n}",

Since this seems to be specific to DocuSign, I was thinking of adding a transformation in RequestBuilder to prune the nil values in a map. This was taken from a closed Posion issue where someone asked for a way to exclude nil values as a feature in Poison( devinus/poison#55).

  @spec add_optional_params(map(), %{optional(atom) => atom}, keyword()) :: map()
  def add_optional_params(request, definitions, [{key, value}] = values) do
    case definitions do
      %{^key => :body} when map_size(definitions) == 1 ->
        # If there is a single entity to send in the body there is no need to
        # enclose it in a multipart request.
        add_param(request, :body, :body, Map.from_struct(value) |> prune_nils())

      _ ->
        do_add_optional_params(request, definitions, values)
    end
  end

  @spec prune_nils(map) :: map
  def prune_nils(s) when is_struct(s), do: s |> Map.from_struct() |> Enum.reduce(%{}, &reducer/2)
  def prune_nils(m) when is_map(m), do: Enum.reduce(m, %{}, &reducer/2)

  @spec reducer({any, any}, map) :: map
  defp reducer({k, v}, map) when is_map(v), do: Map.put(map, k, prune_nils(v))
  defp reducer({_k, v}, map) when is_nil(v), do: map
  defp reducer({k, v}, map), do: Map.put(map, k, v)

Are you OK with this change? I will create a pull request if you are.

@neilberkman
Copy link
Owner

Yes, this would be great. Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants