diff --git a/README.md b/README.md index d500b24..777ba35 100644 --- a/README.md +++ b/README.md @@ -52,3 +52,17 @@ Then you can use client.SignInWithEmailPassword(USER_EMAIL, USER_PASSWORD) ``` + +### Configure HTTP Proxy + +To configure an HTTP Proxy for the Supabase client, you can use the `Proxy` field in `ClientOptions`. Here's an example: + +```go + client, err := supabase.NewClient(API_URL, API_KEY, &supabase.ClientOptions{ + Proxy: "http://your-proxy-url:port", + }) + if err != nil { + fmt.Println("cannot initalize client", err) + } + data, count, err := client.From("countries").Select("*", "exact", false).Execute() +``` diff --git a/client.go b/client.go index edb8c8b..0bcce92 100644 --- a/client.go +++ b/client.go @@ -3,6 +3,8 @@ package supabase import ( "errors" "log" + "net/http" + "net/url" "time" "github.com/supabase-community/functions-go" @@ -32,11 +34,13 @@ type Client struct { type clientOptions struct { url string headers map[string]string + proxy *url.URL } type ClientOptions struct { Headers map[string]string Schema string + Proxy string } // NewClient creates a new Supabase client. @@ -72,12 +76,27 @@ func NewClient(url, key string, options *ClientOptions) (*Client, error) { schema = "public" } - client.rest = postgrest.NewClient(url+REST_URL, schema, headers) - client.Storage = storage_go.NewClient(url+STORAGE_URL, key, headers) + if options != nil && options.Proxy != "" { + proxyURL, err := url.Parse(options.Proxy) + if err != nil { + return nil, err + } + client.options.proxy = proxyURL + } + + httpClient := &http.Client{} + if client.options.proxy != nil { + httpClient.Transport = &http.Transport{ + Proxy: http.ProxyURL(client.options.proxy), + } + } + + client.rest = postgrest.NewClientWithHTTPClient(url+REST_URL, schema, headers, httpClient) + client.Storage = storage_go.NewClientWithHTTPClient(url+STORAGE_URL, key, headers, httpClient) // ugly to make auth client use custom URL - tmp := gotrue.New(url, key) + tmp := gotrue.NewWithHTTPClient(url, key, httpClient) client.Auth = tmp.WithCustomGoTrueURL(url + AUTH_URL) - client.Functions = functions.NewClient(url+FUNCTIONS_URL, key, headers) + client.Functions = functions.NewClientWithHTTPClient(url+FUNCTIONS_URL, key, headers, httpClient) return client, nil } diff --git a/client_test.go b/client_test.go index b14b6d7..4230efc 100644 --- a/client_test.go +++ b/client_test.go @@ -2,6 +2,8 @@ package supabase_test import ( "fmt" + "net/http" + "net/http/httptest" "testing" "github.com/supabase-community/supabase-go" @@ -47,3 +49,94 @@ func TestFunctions(t *testing.T) { result, err := client.Functions.Invoke("hello_world", map[string]interface{}{"name": "world"}) fmt.Println(result, err) } + +func TestFromWithProxy(t *testing.T) { + proxy := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusOK) + w.Write([]byte(`[{"id":1,"name":"Test Country"}]`)) + })) + defer proxy.Close() + + client, err := supabase.NewClient(API_URL, API_KEY, &supabase.ClientOptions{Proxy: proxy.URL}) + if err != nil { + t.Fatalf("cannot initialize client: %v", err) + } + + data, count, err := client.From("countries").Select("*", "exact", false).Execute() + if err != nil { + t.Fatalf("error executing query: %v", err) + } + + expected := `[{"id":1,"name":"Test Country"}]` + if string(data) != expected { + t.Errorf("expected %s, got %s", expected, string(data)) + } + if count != 1 { + t.Errorf("expected count 1, got %d", count) + } +} + +func TestRpcWithProxy(t *testing.T) { + proxy := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusOK) + w.Write([]byte(`"Hello, world!"`)) + })) + defer proxy.Close() + + client, err := supabase.NewClient(API_URL, API_KEY, &supabase.ClientOptions{Proxy: proxy.URL}) + if err != nil { + t.Fatalf("cannot initialize client: %v", err) + } + + result := client.Rpc("hello_world", "", nil) + expected := `"Hello, world!"` + if result != expected { + t.Errorf("expected %s, got %s", expected, result) + } +} + +func TestStorageWithProxy(t *testing.T) { + proxy := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusOK) + w.Write([]byte(`{"id":"bucket-id","name":"Test Bucket"}`)) + })) + defer proxy.Close() + + client, err := supabase.NewClient(API_URL, API_KEY, &supabase.ClientOptions{Proxy: proxy.URL}) + if err != nil { + t.Fatalf("cannot initialize client: %v", err) + } + + result, err := client.Storage.GetBucket("bucket-id") + if err != nil { + t.Fatalf("error getting bucket: %v", err) + } + + expected := `{"id":"bucket-id","name":"Test Bucket"}` + if result != expected { + t.Errorf("expected %s, got %s", expected, result) + } +} + +func TestFunctionsWithProxy(t *testing.T) { + proxy := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusOK) + w.Write([]byte(`{"message":"Hello, world!"}`)) + })) + defer proxy.Close() + + client, err := supabase.NewClient(API_URL, API_KEY, &supabase.ClientOptions{Proxy: proxy.URL}) + if err != nil { + t.Fatalf("cannot initialize client: %v", err) + } + + result, err := client.Functions.Invoke("hello_world", map[string]interface{}{"name": "world"}) + if err != nil { + t.Fatalf("error invoking function: %v", err) + } + + expected := `{"message":"Hello, world!"}` + if result != expected { + t.Errorf("expected %s, got %s", expected, result) + } +}