Skip to content

Commit d205d03

Browse files
committed
major refactor on documenation and client initialisation
1 parent 1453fbf commit d205d03

File tree

6 files changed

+310
-115
lines changed

6 files changed

+310
-115
lines changed

README.md

Lines changed: 95 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22

33
Where the magic starts!
44

5+
> [!WARNING]
6+
> This project is still in high development, expect breaking changes.
7+
58
## Getting Started
69

710
### Installation
@@ -11,7 +14,28 @@ To install the base SDK:
1114
```elixir
1215
def deps do
1316
[
14-
{:supabase_potion, "~> 0.4"}
17+
{:supabase_potion, "~> 0.5"}
18+
]
19+
end
20+
```
21+
22+
### General installation
23+
24+
This library per si is the base foundation to user Supabase services from Elixir, so to integrate with specific services you need to add each client library you want to use.
25+
26+
Available client services are:
27+
- [PostgREST](https://github.com/zoedsoupe/postgres-ex)
28+
- [Storage](https://github.com/zoedsoupe/storage-ex)
29+
- [Auth/GoTrue](https://github.com/zoedsoupe/gotrue-ex)
30+
31+
So if you wanna use the Storage and Auth/GoTrue services, your `mix.exs` should look like that:
32+
33+
```elixir
34+
def deps do
35+
[
36+
{:supabase_potion, "~> 0.5"}, # base SDK
37+
{:supabase_storage, "~> 0.3"}, # storage integration
38+
{:supabase_gotrue, "~> 0.3"}, # auth integration
1539
]
1640
end
1741
```
@@ -39,33 +63,90 @@ A `Supabase.Client` holds general information about Supabase, that can be used t
3963
- `:storage` - storage type
4064
- `:storage_key` - storage key
4165

42-
## Configuration
66+
### Usage
67+
68+
There are two ways to create a `Supabase.Client`:
69+
1. one off clients
70+
2. self managed clients
71+
72+
#### One off clients
73+
74+
One off clients are clients that are created and managed by your application. They are useful for quick interactions with the Supabase API.
75+
76+
```elixir
77+
iex> Supabase.init_client("https://<supabase-url>", "<supabase-api-key>")
78+
iex> {:ok, %Supabase.Client{}}
79+
```
80+
81+
Any additional config can be passed as the third argument:
82+
83+
```elixir
84+
iex> Supabase.init_client("https://<supabase-url>", "<supabase-api-key>", %{db: %{schema: "another"}}})
85+
iex> {:ok, %Supabase.Client{}}
86+
```
87+
88+
For more information on the available options, see the [Supabase.Client](https://hexdocs.pm/supabase_potion/Supabase.Client.html) module documentation.
89+
90+
> There's also a bang version of `Supabase.init_client/3` that will raise an error if the client can't be created.
91+
92+
#### Self managed clients
93+
94+
Self managed clients are clients that are created and managed by a separate process on your application. They are useful for long running applications that need to interact with the Supabase API.
95+
96+
If you don't have experience with processes or is a Elixir begginner, you should take a deep look into the Elixir official getting started section about processes, concurrency and distribution before to proceed.
97+
- [Processes](https://hexdocs.pm/elixir/processes.html)
98+
- [Agent getting started](https://hexdocs.pm/elixir/agents.html)
99+
- [GenServer getting started](https://hexdocs.pm/elixir/genservers.html)
100+
- [Supervison trees getting started](https://hexdocs.pm/elixir/supervisor-and-application.html)
43101

44-
Ensure your Supabase configurations are set:
102+
So, to define a self managed client, you need to define a module that will hold the client state and the client process.
103+
104+
```elixir
105+
defmodule MyApp.Supabase.Client do
106+
use Supabase.Client
107+
end
108+
```
109+
110+
For that to work, you also need to configure the client in your `config.exs`:
45111

46112
```elixir
47113
import Config
48114

49-
config :supabase,
50-
supabase_base_url: System.fetch_env!("SUPABASE_BASE_URL"),
51-
supabase_api_key: System.fetch_env!("SUPABASE_API_KEY"),
115+
config :supabase_potion, MyApp.Supabase.Client,
116+
base_url: "https://<supabase-url>", # required
117+
api_key: "<supabase-api-key>", # required
118+
conn: %{access_token: "<supabase-token>"}, # optional
119+
db: %{schema: "another"} # additional options
52120
```
53121

54-
- `supabase_base_url`: The base URL of your Supabase project! More information on how to find it can be seen on the [next section](#how-to-find-my-supabase-base-url?)
55-
- `supabase_api_key`: The secret of your Supabase project! More information on how to find it can be seen on the [next section](#how-to-find-my-supabase-api-key?)
122+
Then, you can start the client process in your application supervision tree:
56123

57-
Make sure to set the environment variables `SUPABASE_BASE_URL` and `SUPABASE_API_KEY`.
124+
```elixir
125+
defmodule MyApp.Application do
126+
use Application
127+
128+
def start(_type, _args) do
129+
children = [
130+
MyApp.Supabase.Client
131+
]
58132

59-
## Starting a Client
133+
opts = [strategy: :one_for_one, name: MyApp.Supervisor]
134+
Supervisor.start_link(children, opts)
135+
end
136+
end
137+
```
60138

61-
You can start a client using the `Supabase.init_client/1` or `Supabase.init_client!/1` function.
139+
Now you can interact with the client process:
62140

63141
```elixir
64-
iex> Supabase.init_client!(%{conn: %{base_url: "<supa-url>", api_key: "<supa-key>"}})
65-
{:ok, %Supabase.Client{}}
142+
iex> {:ok, %Supabase.Client{} = client} = MyApp.Supabase.Client.get_client()
143+
iex> Supabase.GoTrue.sign_in_with_password(client, email: "", password: "")
66144
```
67145

68-
> Note that if you already set up supabase potion options on your application config, you can safely use `Supabase.init_client/0` or `Supabase.init_client!/0`
146+
For more examples on how to use the client, check clients implementations docs:
147+
- [Supabase.GoTrue](https://hexdocs.pm/supabase_go_true)
148+
- [Supabase.Storage](https://hexdocs.pm/supabase_storage)
149+
- [Supabase.PostgREST](https://hexdocs.pm/supabase_postgrest)
69150

70151
### How to find my Supabase base URL?
71152

config/config.exs

Lines changed: 0 additions & 7 deletions
This file was deleted.

lib/supabase.ex

Lines changed: 21 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -2,71 +2,23 @@ defmodule Supabase do
22
@moduledoc """
33
The main entrypoint for the Supabase SDK library.
44
5-
## Installation
6-
7-
The package can be installed by adding `supabase_potion` to your list of dependencies in `mix.exs`:
8-
9-
def deps do
10-
[
11-
{:supabase_potion, "~> 0.3"}
12-
]
13-
end
14-
15-
## Usage
16-
17-
After installing `:supabase_potion`, you can easily and dynamically manage different `Supabase.Client`!
18-
19-
### Config
20-
21-
The library offers a bunch of config options that can be used to control management of clients and other options.
22-
23-
- `manage_clients` - whether to manage clients automatically, defaults to `true`
24-
25-
You can set up the library on your `config.exs`:
26-
27-
config :supabase, manage_clients: false
28-
29-
### Clients
30-
31-
A `Supabase.Client` holds general information about Supabase, that can be used to intereact with any of the children integrations, for example: `Supabase.Storage` or `Supabase.UI`.
32-
33-
`Supabase.Client` is defined as:
34-
35-
- `:conn` - connection information, the only required option as it is vital to the `Supabase.Client`.
36-
- `:base_url` - The base url of the Supabase API, it is usually in the form `https://<app-name>.supabase.co`.
37-
- `:api_key` - The API key used to authenticate requests to the Supabase API.
38-
- `:access_token` - Token with specific permissions to access the Supabase API, it is usually the same as the API key.
39-
- `:db` - default database options
40-
- `:schema` - default schema to use, defaults to `"public"`
41-
- `:global` - global options config
42-
- `:headers` - additional headers to use on each request
43-
- `:auth` - authentication options
44-
- `:auto_refresh_token` - automatically refresh the token when it expires, defaults to `true`
45-
- `:debug` - enable debug mode, defaults to `false`
46-
- `:detect_session_in_url` - detect session in URL, defaults to `true`
47-
- `:flow_type` - authentication flow type, defaults to `"web"`
48-
- `:persist_session` - persist session, defaults to `true`
49-
- `:storage` - storage type
50-
- `:storage_key` - storage key
51-
52-
535
## Starting a Client
546
55-
You then can start a Client calling `Supabase.init_client/1`:
7+
You then can start a Client calling `Supabase.init_client/3`:
568
57-
iex> Supabase.init_client(%{db: %{schema: "public"}})
9+
iex> Supabase.init_client("base_url", "api_key", %{db: %{schema: "public"}})
5810
{:ok, %Supabase.Client{}}
5911
6012
## Acknowledgements
6113
6214
This package represents the base SDK for Supabase. That means
6315
that it not includes all of the functionality of the Supabase client integrations, so you need to install each feature separetely, as:
6416
65-
- [auth](https://github.com/zoedsoupe/gotrue-ex)
66-
- [storage](https://github.com/zoedsoupe/storage-ex)
67-
- [postgrest](https://github.com/zoedsoupe/postgrest-ex)
68-
- `realtime` - TODO
69-
- `ui` - TODO
17+
- [Auth/GoTrue](https://github.com/zoedsoupe/gotrue-ex)
18+
- [Storage](https://github.com/zoedsoupe/storage-ex)
19+
- [PostgREST](https://github.com/zoedsoupe/postgrest-ex)
20+
- `Realtime` - TODO
21+
- `UI` - TODO
7022
7123
### Supabase Storage
7224
@@ -80,7 +32,7 @@ defmodule Supabase do
8032
8133
Supabase Realtime provides a realtime websocket API powered by PostgreSQL notifications. It allows you to listen to changes in your database, and instantly receive updates as soon as they happen.
8234
83-
### Supabase Auth
35+
### Supabase Auth/GoTrue
8436
8537
Supabase Auth is a feature-complete user authentication system. It provides email & password sign in, email verification, password recovery, session management, and more, out of the box.
8638
@@ -95,46 +47,37 @@ defmodule Supabase do
9547

9648
@typep changeset :: Ecto.Changeset.t()
9749

98-
@spec init_client(Client.params() | %{}) :: {:ok, Client.t()} | {:error, changeset}
99-
def init_client(opts \\ %{}) do
50+
@spec init_client(String.t(), String.t(), Client.params() | %{}) :: {:ok, Client.t()} | {:error, changeset}
51+
def init_client(url, api_key, opts \\ %{})
52+
when is_binary(url) and is_binary(api_key) do
10053
opts
101-
|> Map.get(:conn, %{})
102-
|> maybe_merge_config_from_application(opts)
54+
|> Map.put(:conn, %{base_url: url, api_key: api_key})
55+
|> Map.update(:conn, opts, &Map.merge(&1, opts[:conn]))
10356
|> Client.parse()
10457
end
10558

106-
def init_client!(%{} = opts \\ %{}) do
107-
conn = Map.get(opts, :conn, %{})
108-
opts = maybe_merge_config_from_application(conn, opts)
109-
110-
case init_client(opts) do
59+
@spec init_client!(String.t, String.t, Client.params | %{}) :: Client.t() | no_return
60+
def init_client!(url, api_key, %{} = opts \\ %{})
61+
when is_binary(url) and is_binary(api_key) do
62+
case init_client(url, api_key, opts) do
11163
{:ok, client} ->
11264
client
11365

11466
{:error, changeset} ->
11567
errors = errors_on_changeset(changeset)
11668

117-
if "can't be blank" in get_in(errors, [:conn, :api_key]) do
118-
raise MissingSupabaseConfig, :key
69+
if "can't be blank" in (get_in(errors, [:conn, :api_key]) || []) do
70+
raise MissingSupabaseConfig, key: :key, client: nil
11971
end
12072

121-
if "can't be blank" in get_in(errors, [:conn, :base_url]) do
122-
raise MissingSupabaseConfig, :url
73+
if "can't be blank" in (get_in(errors, [:conn, :base_url]) || []) do
74+
raise MissingSupabaseConfig, key: :url, client: nil
12375
end
12476

12577
raise Ecto.InvalidChangesetError, changeset: changeset, action: :init
12678
end
12779
end
12880

129-
defp maybe_merge_config_from_application(%{base_url: _, api_key: _}, opts), do: opts
130-
131-
defp maybe_merge_config_from_application(%{}, opts) do
132-
base_url = Application.get_env(:supabase_potion, :supabase_base_url)
133-
api_key = Application.get_env(:supabase_potion, :supabase_api_key)
134-
135-
Map.put(opts, :conn, %{base_url: base_url, api_key: api_key})
136-
end
137-
13881
defp errors_on_changeset(changeset) do
13982
Ecto.Changeset.traverse_errors(changeset, fn {message, opts} ->
14083
Regex.replace(~r"%{(\w+)}", message, fn _, key ->

0 commit comments

Comments
 (0)