GithubHelp home page GithubHelp logo

nedpals / supabase-go Goto Github PK

View Code? Open in Web Editor NEW
335.0 9.0 58.0 30 KB

Unofficial Supabase client library for Go.

Home Page: https://pkg.go.dev/github.com/nedpals/supabase-go

License: MIT License

Go 100.00%
supabase supabase-client golang api postgrest

supabase-go's Introduction

supabase-go

Unofficial Supabase client for Go. It is an amalgamation of all the libraries similar to the official Supabase client.

Installation

go get github.com/nedpals/supabase-go

Usage

Replace the <SUPABASE-URL> and <SUPABASE-URL> placeholders with values from https://supabase.com/dashboard/project/YOUR_PROJECT/settings/api

Authenticate

package main
import (
    supa "github.com/nedpals/supabase-go"
    "fmt"
    "context"
)

func main() {
  supabaseUrl := "<SUPABASE-URL>"
  supabaseKey := "<SUPABASE-KEY>"
  supabase := supa.CreateClient(supabaseUrl, supabaseKey)

  ctx := context.Background()
  user, err := supabase.Auth.SignUp(ctx, supa.UserCredentials{
    Email:    "[email protected]",
    Password: "password",
  })
  if err != nil {
    panic(err)
  }

  fmt.Println(user)
}

Sign-In

package main
import (
    supa "github.com/nedpals/supabase-go"
    "fmt"
    "context"
)

func main() {
  supabaseUrl := "<SUPABASE-URL>"
  supabaseKey := "<SUPABASE-KEY>"
  supabase := supa.CreateClient(supabaseUrl, supabaseKey)

  ctx := context.Background()
  user, err := supabase.Auth.SignIn(ctx, supa.UserCredentials{
    Email:    "[email protected]",
    Password: "password",
  })
  if err != nil {
    panic(err)
  }

  fmt.Println(user)
}

Insert

package main
import (
    supa "github.com/nedpals/supabase-go"
    "fmt"
)

type Country struct {
  ID      int    `json:"id"`
  Name    string `json:"name"`
  Capital string `json:"capital"`
}

func main() {
  supabaseUrl := "<SUPABASE-URL>"
  supabaseKey := "<SUPABASE-KEY>"
  supabase := supa.CreateClient(supabaseUrl, supabaseKey)

  row := Country{
    ID:      5,
    Name:    "Germany",
    Capital: "Berlin",
  }

  var results []Country
  err := supabase.DB.From("countries").Insert(row).Execute(&results)
  if err != nil {
    panic(err)
  }

  fmt.Println(results) // Inserted rows
}

Select

package main
import (
    supa "github.com/nedpals/supabase-go"
    "fmt"
)

func main() {
  supabaseUrl := "<SUPABASE-URL>"
  supabaseKey := "<SUPABASE-KEY>"
  supabase := supa.CreateClient(supabaseUrl, supabaseKey)

  var results map[string]interface{}
  err := supabase.DB.From("countries").Select("*").Single().Execute(&results)
  if err != nil {
    panic(err)
  }

  fmt.Println(results) // Selected rows
}

Update

package main
import (
    supa "github.com/nedpals/supabase-go"
    "fmt"
)

type Country struct {
  Name    string `json:"name"`
  Capital string `json:"capital"`
}

func main() {
  supabaseUrl := "<SUPABASE-URL>"
  supabaseKey := "<SUPABASE-KEY>"
  supabase := supa.CreateClient(supabaseUrl, supabaseKey)

  row := Country{
    Name:    "France",
    Capital: "Paris",
  }

  var results map[string]interface{}
  err := supabase.DB.From("countries").Update(row).Eq("id", "5").Execute(&results)
  if err != nil {
    panic(err)
  }

  fmt.Println(results) // Updated rows
}

Delete

package main
import (
    supa "github.com/nedpals/supabase-go"
    "fmt"
)

func main() {
  supabaseUrl := "<SUPABASE-URL>"
  supabaseKey := "<SUPABASE-KEY>"
  supabase := supa.CreateClient(supabaseUrl, supabaseKey)

  var results map[string]interface{}
  err := supabase.DB.From("countries").Delete().Eq("name", "France").Execute(&results)
  if err != nil {
    panic(err)
  }

  fmt.Println(results) // Empty - nothing returned from delete
}

Invite user by email

package main
import (
    supa "github.com/nedpals/supabase-go"
    "fmt"
    "context"
)

func main() {
  supabaseUrl := "<SUPABASE-URL>"
  supabaseKey := "<SUPABASE-KEY>"
  supabase := supa.CreateClient(supabaseUrl, supabaseKey)

  ctx := context.Background()
  user, err := supabase.Auth.InviteUserByEmail(ctx, email)
  if err != nil {
    panic(err)
  }

  // or if you want to setup some metadata
  data := map[string]interface{}{ "invitedBy": "someone" }
  redirectTo := "https://your_very_successful_app.com/signup"
  user, err = supabase.Auth.InviteUserByEmailWithData(ctx, email, data, redirectTo)
  if err != nil {
    panic(err)
  }

  fmt.Println(user)
}

Roadmap

  • Auth support (1)
  • DB support (2)
  • Realtime
  • Storage
  • Testing

(1) - Thin API wrapper. Does not rely on the GoTrue library for simplicity (2) - Through postgrest-go

I just implemented features which I actually needed for my project for now. If you like to implement these features, feel free to submit a pull request as stated in the Contributing section below.

Design Goals

It tries to mimick as much as possible the official Javascript client library in terms of ease-of-use and in setup process.

Contributing

Submitting a pull request

  • Fork it (https://github.com/nedpals/supabase-go/fork)
  • Create your feature branch (git checkout -b my-new-feature)
  • Commit your changes (git commit -am 'Add some feature')
  • Push to the branch (git push origin my-new-feature)
  • Create a new Pull Request

Contributors

supabase-go's People

Contributors

arobert93 avatar bastianwegge avatar charamza avatar darwishdev avatar dvcrn avatar fritte795 avatar hkdb avatar iamajoe avatar jackmerrill avatar jessp01 avatar masudur-rahman avatar nedpals avatar nzoschke avatar omietejl avatar rscorer avatar surendrakandel avatar tom-draper avatar whoiscarlo avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

supabase-go's Issues

Filter eq with reserved characters does not seem to need %22

I stumbled across a weird behavior where I could not use a filter with eq to filter by an IP-Address (e.g. 10.0.0.1).
The generated url for From("Foo").Select("*").Eq("ip", "10.0.0.1").Execute() is /rest/v1/Foo?select=%2A&vpn_ip=eq.%2210.0.0.1%22. As the PostgrestAPI states, when using reserved characters we have to use percent encoded double quotes %22 for correct processing (Source).
This library correctly identifies the reserved characters and does as the documentation states. Unfortunately the result is always empty.
Using the generated URL in a curl request confirms that an empty result is returned.

Interestingly it is possible to perform following curl request and receiving the expected single result:

/rest/v1/Foo?select=%2A&vpn_ip=eq.10.0.0.1

Note the missing " or %22 in the request above.

With some further research I could identify a different behaviour in the official postgrest-js. It appears that not all filters must recognize reserved chars. On first glance it mainly is the in filter.

If you could confirm this @nedpals I could prepare a pull request until next week.

Edit: I would open this issue in the corresponding repository if issues were possible (nedpals/postgrest-go)

Select on insert

Hi, I'm curious how to get the ID of an inserted row.

For other SDK it looks like you perform a .Select() after the insert, but this doesn't look to be supported here.

Offical js SDK

const { data, error } = await supabase
  .from('countries')
  .insert({ id: 1, name: 'Denmark' })
  .select()

Expected - supabase-go
supabase.DB .From("Table") .Insert(row) .Select() .Execute(&result)

Counting number of rows returned by a SELECT

How to count the number of rows returned by a select query? The following code throws error "failed to count messages in thread: PGRST200: Could not find a relationship between 'message' and 'COUNT' in the schema cache":

var messageCount int64
err = s.supabaseClient.DB.From("message").Select("COUNT(*)").Eq("thread_id", threadID).Execute(&messageCount)

Auth with PKCE

Great project, I got the first version of an supabase auth provider working in 5 minutes. However its using implicit flow, so the access_token is in a URL fragment and not available on the server side.

From the auth server side rendering docs, I need to configure the auth client to use PKCE flow by setting the flowType: 'pkce' some how.

I'm thinking this will either be a new option on ProviderSignInOptions or to CreateClient.

I plan to work on this an open a PR, but starting with an issue here in case anyone else has the problem or knows the solution.

storage is unusable in v0.2.0

When i use DeleteBucket(), it panics because nil pointer error.
The error is caused by this line https://github.com/nedpals/supabase-go/blob/master/storage.go#L166

It tries to access s.client, but is a nil pointer.
The same with any method that tries to access Storage's client field in storage.go.

PROBLEM:
When initializing the supabase client with CreateClient, the in v.0.2.0 Storage's client is not SET.
(idk if it's the only problem).

FIX:
this commit (almost 5 months ago) already fixes the problem by setting the storage's client field in CreateClient(), but isn't present in the latest version (v0.2.0).

pls release a new version with the fix

Realtime feature

Hello guys :)

Are you planning to implement realtime updates?

Post "/rest/v1/[tableName]": unsupported protocol scheme ""

It shows this error Post "/rest/v1/emails": unsupported protocol scheme "" when deploying from render.com server but it works fine locally. I don't know where the problem is

type Emaildb struct {
	Name    string `json:"name"`
	Subject string `json:"subject"`
	To      string `json:"to"`
	Text    string `json:"text"`
	Date   string `json:"date"`
}

func AddMail(m Emaildb) {
	supabaseUrl := os.Getenv("SUPABASE_URL")
	supabaseKey := os.Getenv("SUPABASE_PRIVATE_KEY_SERVICE_ROLE")
	supabase := supa.CreateClient(supabaseUrl, supabaseKey)

	var results []types.Email

	err := supabase.DB.From("emails").Insert(m).Execute(&results)
	if err != nil {
		fmt.Println("cant insert email to db" + err.Error())
	}

	fmt.Println(results)
}

Failed to get Auth.User Token

I was trying to get User by token, the token coming from supabase.auth.currentSession.access_token (on flutter) and after that, I can't get the data user base on the token. do you know how to solved it?

JWT Token expired Issue

When using the client.Auth.User() function, if the JWT token is expired, the returned error is initialized but without the internal Error() function, meaning the error is not nil and there's no message.

I had to verify the value returned variable for error handling instead:
image

Looking for help to figure out what Supabase functions these RequestBuilder methods connect to?

Hey I was wondering if there is a way to find out what these functions do?

Like
Ilike
Fts
Plfts
Phfts
Wfts
Cs
Cd
Ov
Sl
Sr
Nxl
Nxr
Adj

The intellisense for VS code gives no real information about any of the function or what they do, the file github.com/nedpals/postgrest-go/pkg/request_builder.go doesn't have comments about them, and I can't figure out which Supabase function they correlate to.

Would anyone be able to provide some insight or help me figure them out?

Auth.SignUp without password does not work

As the title states, running some code like this:

s := supa.CreateClient(os.Getenv("SUPABASE_URL"), os.Getenv("SUPABASE_SERVICE_KEY"))
ctx := context.Background()
user, err := s.Auth.SignUp(ctx, supa.UserCredentials{
    Email: "[email protected]",
})
if err != nil {
    return err
}

Results in no user being created, and what's even more interesting is that err is not nil, but just an empty string! Would be intested in what is going wrong here, or perhaps what I am missing. (already doublechecked that the env vars are correct)

UPDATE: Okay, passing a random value for a password actually creates the user (note as per the docs the password is not required - referencing v1 docs here as I assume that is what this library is based off of). Then the next issue: the full user object isn't returned, I only get something like this:

{    0001-01-01 00:00:00 +0000 UTC 0001-01-01 00:00:00 +0000 UTC 0001-01-01 00:00:00 +0000 UTC {} map[] 0001-01-01 00:00:00 +0000 UTC 0001-01-01 00:00:00 +0000 UTC}

Provision redirectTo for the go sdk

is it possible to pass the redirectTO parameter for the signup confirmation mail sent by supabase just like its done in the js syntax

async function signUpNewUser() { const { data, error } = await supabase.auth.signUp({ email: '[email protected]', password: 'example-password', options: { emailRedirectTo: 'https://example.com/welcome', }, }) }

DELETE requires a WHERE clause

Hi, thanks for writing this package. I'm trying to delete all rows in a table (see below)

This:

  var results map[string]interface{}
  err := supabase.DB.From("events").Delete().Execute(&results)
  if err != nil {
    panic(err)
  }

Panics with this:

panic: 21000: DELETE requires a WHERE clause

It seems incongruous that this is required:

err := supabase.DB.From("events").Delete().Like("evt_name","*").Execute(&results)

When this just works in Postgres:

DELETE from events

Is this a bug or a feature or am I missing something?

Thanks in advance.

GORM support

Is there any target for using pgx or GORM support for this project?

Update Doku for nested select

Hey, since I just spend multiple hours on this problem, I thought it could be worth taking it as example.

When making a nested request, e.g. select=user!inner (name), id&user.name=eq.foo, there could be two errors. First that it is not parsable. The reason would be the space after the inner.

The second problem is, that it is not possible to use a nested string like "user.name", because the dot is a reserved char. As consequence the library will change it to ""user.name"" and the request fails with the statement:
42703: column Foo.user.name does not exist

A simple solution for this would be to use backticks instead of using a double quotation mark.

I think, that updating the docs to make this understandable could lower much pain

rpc error

Hello,
I've tried to use the client rpc call with something like:

client.DB.Rpc("search",....)

but I get the error:

Post "/rpc/public/search": unsupported protocol scheme ""

I think there's an issue with the baseURL in the client maybe? can you help? thanks

Postgrest-go Repository

Hey @nedpals ,
unfortunately I have no other way to reach out.

Two requests:

  1. Could you please enable "Issues" in postgrest-go
  2. Could you also please prepare a new Release (Tag) so that I could implement the new library version into the supabase repo?

cannot unmarshal array into Go value of type RequestError

Based on the sparse readme examples, I've got an insert query that looks like

var results map[string]interface{}  // I also tried the type RequestError, no luck
err := supaClient.DB.From("table").Insert(user).Execute(results)

All other operations I've tried yield similar results. Any ideas on how to avoid this error being returned? The operations seem to be working in Supabase (rows are inserted), but the err object is always this message.

Also, I have no idea how to go about building queries with this wrapper, are there any resources to point to? I'm glad to write up some docs for this wrapper if I can get some guidance.

Thanks for the work of putting this together!

Auth issue, anon working

Hi all, I may be doing something stupid here so please forgive me.

When i run a sign in, how do i then use that logged in user to perform requests against the DB?

My query is working with RLS allowing anon however when RLS is enabled to only allow authenticated users I don't get a response.

I've tried multiple ways of enabling auth only for SELECT on the table. for example:

CREATE POLICY "Enable read accesas for authenticated users" ON "public"."TESTTABLE"
AS PERMISSIVE FOR SELECT
TO authenticated
USING (true)

My call to signIn does also respond with a user token.

In supabase logs it appears that no auth header is added to the requests:

"headers": [
          {
            "accept": "application/json",
            "cf_cache_status": null,
            "cf_connecting_ip": "xxxx",
            "cf_ipcountry": "xx",
            "cf_ray": "xxx",
            "content_length": "4",
            "content_location": null,
            "content_range": null,
            "content_type": "application/json",
            "date": null,
            "host": "xxxx.supabase.co",
            "prefer": null,
            "range": null,
            "referer": null,
            "sb_gateway_version": null,
            "user_agent": "Go-http-client/2.0",
            "x_client_info": null,
            "x_forwarded_proto": "https",
            "x_forwarded_user_agent": null,
            "x_kong_proxy_latency": null,
            "x_kong_upstream_latency": null,
            "x_real_ip": "xxx"
          }

Any help would be appreciated

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.