- Supabase has a concept of functions. These are code written in typescript,
meant for deno code that gets deployed by supabase on their edge locations.
- Each "function" is a standalone application, with it's own deployment,
configuration, logs etc.
- you create a new "function" using `supabase functions new the-name`
- this command creates a folder named `supabase/functions/the-name`, with a file
containing `index.ts` which looks like this:
import { serve } from "https://deno.land/[email protected]/http/server.ts"
console.log("Hello from Functions!")
serve(async (req) => {
const { name } = await req.json()
const data = {
message: `Hello ${name}!`,
}
return new Response(
JSON.stringify(data),
{ headers: { "Content-Type": "application/json" } },
)
})
- to test the function locally you have to start supabase using `supabase
start` and then run functions, `supabase functions serve`
- to call the function locally you have to do this:
curl --request POST 'http://localhost:54321/functions/v1/the-name' \n --header 'Authorization: Bearer <anon key>' \n --header 'Content-Type: application/json' \n --data '{ "name": "Functions" }'
- on local the anon key header is optional
- functions are deployed on multiple servers all around the world and supposedly
have low latency benefits.
- on each location, probably one instance of the "function server" runs, they
auto restart the server when needed.
- function server can be thought as a standlone server, written in deno, running
somewhere.
- the "Hello from Functions!" is printed when the "function server" starts.
- the server probably starts on demand as there are many locations and there is
no need to keep all of them running. In the logs I only saw one "hello from
functions!" printed, so it probably started one even when there was no
request, maybe to assure me, that it is indeed deployed.
- the function passed to `serve()` is called on every function request.
connecting to db from function
import * as postgres from 'https://deno.land/x/[email protected]/mod.ts'
import { serve } from 'https://deno.land/[email protected]/http/server.ts'
// Get the connection string from the environment variable "SUPABASE_DB_URL"
const databaseUrl = Deno.env.get('SUPABASE_DB_URL')!
// Create a database pool with three connections that are lazily established
const pool = new postgres.Pool(databaseUrl, 3, true)
serve(async (_req) => {
try {
// Grab a connection from the pool
const connection = await pool.connect()
try {
// Run a query
const result = await connection.queryObject`SELECT * FROM animals`
const animals = result.rows // [{ id: 1, name: "Lion" }, ...]
console.log(animals)
// Encode the result as pretty printed JSON
const body = JSON.stringify(
animals,
(key, value) => (typeof value === 'bigint' ? value.toString() : value),
2
)
// Return the response with the correct content type header
return new Response(body, {
status: 200,
headers: {
'Content-Type': 'application/json; charset=utf-8',
},
})
} finally {
// Release the connection back into the pool
connection.release()
}
} catch (err) {
console.error(err)
return new Response(String(err?.message ?? err), { status: 500 })
}
})
Template strings for [safe query arguments](https://deno-postgres.com/#/?id=template-strings)
const min = 10;
const max = 20;
const result = await connection
.queryObject`SELECT ID, NAME FROM PEOPLE WHERE AGE > ${min} AND AGE < ${max}`;
console.log(result.rows);
- `connection.queryObject`SELECT * FROM animals`