chulkilee / ex_force

A Salesforce REST API wrapper for Elixir
https://hex.pm/packages/ex_force
MIT License
38 stars 28 forks source link

Split request build and perform steps #6

Closed chulkilee closed 6 years ago

chulkilee commented 7 years ago

Currently functions take arguments and ExForce.Config (for authentication), perform the request, and return optionally transformed response.

config = %ExForce.Config{}

{:ok, resp} = ExForce.query(soql, config)
{:ok, resp} = ExForce.describe_sobject("Account", config)

The main drawback of this approach is that all functions need ExForce.Config for authentication.

A way to avoid that is to make a request struct, and use separate general request handler taking the request.

config = %ExForce.Config{}

{:ok, result} = soql |> ExForce.query() |> ExForce.request(config)

stream = soql |> ExForce.query() |> ExForce.stream_query(config)

ex_aws is taking this approach.

There are several way to implement this interface.

Use general-purpose request struct

@spec get_sobject(sobject_id, sobject_name, list) :: Request.t()

@spec request(Request.t()) :: {:ok, any} | {:error, any}

Use different request struct

@spec get_sobject(sobject_id, sobject_name, list) :: SObjectRequest.t()

@spec request(SObjectRequest.t()) :: {:ok, SObject.t()} | {:error, any}

For example, ExAws uses ExAws.Operation protocol for perform(ops, config) - ref.

Return func

@type request_func :: ((config_or_func) -> {:ok, any} | {:error, any})

@spec get_sobject(sobject_id, sobject_name, list) :: ((config_or_func) -> {:ok, SObject.t()} | {:error, any})

@spec request(request_func) :: {:ok, any} | {:error, any}
chulkilee commented 6 years ago

Per #17 I'm going to replace roll-your-own request/response (using HTTPoison) with Tesla.

This separation of request/response step looks nice, but it does not give significant benefits.

Closing it.