Nathan Lamont

Notes to Self

Supabase

Experimentally using for playkode.com reboot.

Free tier has

  • unlimited API calls
  • 50K monthly active users
  • 500MB DB space
  • 5GB Bandwidth
  • 1GB File storage
  • 2 active projects at a time

Has

  • Authentication
  • Postgres
  • File storage
  • Cloud functions

Client can basically query Postgres, with both row-level and column-level auth possible. That’s great.

Possibly harder, more complicated API calls can be done with “edge” functions (functions in the cloud). But you are tempted to move as much logic to the client as possible, as long as data integrity doesn’t become an issue (for example, client is quit in the middle of a multi-step process). Does Supabase allow transactions? No way they’d be possible outside of an edge function?

Stackflow answer suggests Postgres function or trigger.

Snippets of Interest

To Manage Auth Policy with Indirect Ownership?

In my case, a user has many projects. A project has many codes. How to know if a code can be updated by user?

Auth policy for UPDATE looks like:

create policy "Update code in projects user owns"
  on "public"."code"
  as permissive for update to authenticated using (
    (( SELECT auth.uid() AS uid) IN (
      SELECT projects.user_id FROM projects WHERE (
          code.project_id = projects.id
        )
      )
    )
  );

To Use an Edge Function From Web Client

https://supabase.com/docs/guides/functions/cors for postgres: https://supabase.com/docs/guides/functions/connect-to-postgres

Edge function:

Deno.serve(async (req) => {
  const corsHeaders = {
    'Access-Control-Allow-Origin': '*',
    'Access-Control-Allow-Headers': 'authorization, x-client-info, apikey, content-type',
  }

 if (req.method === 'OPTIONS') {
     return new Response('ok', { headers: corsHeaders })
   }

   try {
     const { name } = await req.json()
     const data = {
       message: `Hello ${name}!`,
     }

     return new Response(JSON.stringify(data), {
       headers: { ...corsHeaders, 'Content-Type': 'application/json' },
       status: 200,
     })
   } catch (error) {
     return new Response(JSON.stringify({ error: error.message }), {
       headers: { ...corsHeaders, 'Content-Type': 'application/json' },
       status: 400,
     })
   }
})

Client:

const { data, error } = await supabase.functions.invoke('hello-world', {
    body: { name: 'Foobar' }
  })

Create an edge function:

$ supabase functions new <function-name>

Deploy an edge function:

$ supabase functions deploy <function-name>
$ supabase functions deploy # deploys all functions

To Install CLI

You used go method (not Homebrew). Was installed in ~/go/bin as cli so you renamed it to supabase

Unanswered Questions

  • How to do database migrations? Can all this config be expressed in code & put under version control & made repeatable?
  • Edge functions in particular; local testing? Must always be deployed individually, manually?