zoedsoupe / supabase-ex

A complete Toolkit to interact with Supabase APIs from Elixir
https://hexdocs.pm/supabase_potion
MIT License
107 stars 3 forks source link

(Quesiton): Need some clarification about configuring the supabase client #40

Closed qwexvf closed 3 months ago

qwexvf commented 3 months ago

Hi. I came across this amazing lib and got some errors during setup(pherhaps outdated docs?)

a few quesitons

  1. is config part supposed to be the below?
    # Configures Supabase
    config :supabase,
    manage_clients: false,
    supabase_base_url: System.fetch_env!("SUPABASE_BASE_URL"),
    supabase_api_key: System.fetch_env!("SUPABASE_API_KEY")

and not this?

# Configures Supabase
config :supabase_potion,
  manage_clients: false,
  supabase_base_url: System.fetch_env!("SUPABASE_BASE_URL"),
  supabase_api_key: System.fetch_env!("SUPABASE_API_KEY")
  1. How can i initialize a supabase client when using phoenix? using the config above in my application.ex i have the code below

    defmodule Apllication do
    @impl true
    def start(_type, _args) do
    children = [
    ....
      Supabase.Supervisor # init the supervisor?
    ]
    Supervisor.start_link(children, opts)
    end
    
    ....
    end

Now where should i init the client?

i can confirm running Supabase.Client.init_client!(%{conn: %{base_url: "<supa-url>", api_key: "<supa-key>"}}) {:ok, #PID<0.123.0>} in iex works as expected.

I'm also confused about the manage_clients option. If i do manage_clients: true i don't need to init a client? Sorry about the noobish questions i really appreciate your work after getting some answers i can fix the docs and maybe create provide a phoenix example in this repo let me know your thoughts!

qwexvf commented 3 months ago

i figured nice way of initializing by manual

defmodule Supabase do
  @moduledoc """
  The Supabase context.
  """

  @client_name __MODULE__

  defp client do
    Supabase.init_client(%{
      name: @client_name,
      conn: %{
        base_url: config().base_url,
        api_key: config().api_key
      }
    })
    |> case do
      {:ok, pid} -> pid
      {:error, {:already_started, pid}} -> pid
      error -> raise "Failed to initialize Supabase client: #{inspect(error)}"
    end
  end

  def config do
    %{
      base_url: System.fetch_env!("SUPABASE_BASE_URL"),
      api_key: System.fetch_env!("SUPABASE_ANON_KEY")
    }
  end

  # retrive a user frm jwt token
  def get_user(session) do
    client()
    |> Supabase.GoTrue.get_user(session)
  end
end

but I'm still confused by how this will work without manage_clients: false

zoedsoupe commented 3 months ago

Hi there thank you for using the library!

So let's unveil each of the question parts:

  1. indeed there are some outdated docs, so the correct way to setup supabase library config is the second option, as:

    config :supabase_potion,
    manage_clients: true,
    supabase_base_url: System.get_env("SUPABASE_URL"),
    supabase_api_key: System.get_env("SUPABASE_KEY")
  2. how does :manage_clients config works and how to start clients?

The :manage_clients option exists to provide you a way to manage clients manually (which differs from starting them). When you pass manage_clients: true, the Supabase Potion library you start a supervision tree with Supabase.ClientRegistry and Supabase.ClientSupervisor for you, so you can issue

Supabase.init_client!(:my_conn) # #PID<1.2.3>

If you don't want to client being managed automatically, you can start these 2 modules, you have several ways to manage and start clients:

a. put Supabase.ClientRegistry and Supabase.ClientSupervisor to your supervision tree and se tup manage_clients: false to the lib config.

b. start a single client manually to your supervision tree:

defmodule MyApp.Application do
  use Application

  @impl true
  def start(_type, _args) do
    supabase_config = supabase_client_config()
    supabase_opts = [name: MyApp.SupabaseClient, client_info: supabase_config]

    children = [
      # rest of your Supervisor's children...
      {Supabase.Client, supabase_opts}
    ]
  end

  defp supabase_client_config do
    %{
      # you can skip the `conn` config if you already set on config.exs
      conn: %{ 
        api_key: "my-super-secret-api-key",
        base_url: "https://my-project-id.supabase.co",
        access_token: "my-scoped-access-token",
      },
      db: %{schema: "my-schema"} # default to "public",
      # global headers to be used on Supabase API requests
      global: %{headers: %{"content-type": "application/json"}},
      auth: %{
        # below are the defaults values
        auto_refresh_token: true,
        debug: false,
        detect_session_in_url: true,
        flow_type: :implicit,
        persist_session: true,
        storage: "my-storage",
        storage_key: "my-storage-key"
      }
    }
  end

  # rest of module...
end

c. create a module in you application that you serve as a Facade to the Supabase client:

# lib/my_app/supabase.ex
defmodule MyApp.Supabase do
  defmodule Auth do
    use Supabase.GoTrue, client: MyApp.Supabase.Auth
  end

  def start_link(_opts) do
    children = [__MODULE__.Auth]
    opts = [strategy: :one_for_one, name: __MODULE__]
    Supervisor.start_link(children, opts)
  end

  def child_spec(opts) do
    %{
      id: __MODULE__,
      start: {__MODULE__, :start_link, [opts]},
      type: :worker,
      restart: :permanent,
      shutdown: 500
    }
  end
end

# lib/my_app/application.ex
defmodule MyApp.Application do
  use Application

  @impl true
  def start(_type, _args) do
    children = [
      MyApp.Supabase
    ]
  end

  # rest of module...
end

With this option you don't even need to call Supabase.init_client!/2! You can start using it as MyApp.Supabase.Auth.sign_in_with_password/1, for example.

Conclusion

So these solutions clarify the library usage and how to manage/start clients?

qwexvf commented 3 months ago

Hey thanks for the quick response your answer made clear to my doubts!! Now i understood the purpose of manually handling the supervisors etc.. I end up using the option c which is easier for me at the moment! Thank you again.

Additionally, I have submitted a pull request to address the outdated documentation. Could you kindly review it at your earliest convenience? Thank you very much!