API Clients Design

Hey there, I am working with a client for an OpenAPI spec, and I have a dilemma.

Imagine the following

defmodule API.Account do
  @moduledoc """
  Implements /account endpoints.

  alias StrawHat.Response
  alias API.{Client, Client.Request}

  @type t :: %__MODULE__{
          email: String.t(),
          id: String.t(),
          is_international: boolean()

  defstruct [:email, :id, :is_international]

  @doc """
  Retrieve account information.
  @spec get_account(%Client{}) :: Response.t(%__MODULE__{}, Client.error())
  def get_account(client) do
    |> Request.new()
    |> Request.put_method(:get)
    |> Request.put_path("/account")
    |> Client.send()
    |> StrawHat.Response.and_then(&transform_response/1)

  @doc false
  def new(data) do
      email: data["email"],
      id: data["id"],
      is_international: data["isInternational"]

  defp transform_response(data) do
    |> new()
    |> Response.ok()

Here is my dilemma: Should I transform the incoming data into structs, or I shouldn’t bother with it?

I am talking about the following part

    |> StrawHat.Response.and_then(&transform_response/1)

Should I keep that? Or should I just return the raw data?

I still don’t know what the right answer is here honestly.

From one side, it is a lot of work and I think doesn’t matter much, not sure.
From the otherwise, it is nice, I get to have structs and normalize a bit the keys and such.

1 Like

My personal preference is to return raw, so that you don’t have to keep up with the api as closely, and don’t have to distinguish between versions as strictly.

1 Like

If I’m writing an API client where I work with the data (as opposed to just passing it to somewhere else), I usually add the request and response structs. This makes the API more discoverable without the need to reach to the API documentation. But this is not a universal advice - there are scenarios where you don’t care about the response, so why waste the time on building a reach response.

1 Like