One of the latest feature introduced by Supabase is Edge Functions:
- Server-side functions
- Distributed globally at the edge, close to your users (low latency)
- Used for listening to webhooks or integrating your Supabase project with third-parties services
Edge functions in Supabase are generally written in Typescript. Nonetheless, a new package called edge allows you to implement edge functions in dart 🎯
In this post, we are going to setup a new project to implement your first edge function on Supabase in Dart.
Note: Dart Edge is an experimental project. It's probably not ready for production yet ☝️
Setting up edge
The first step is installing and activating the edge CLI by running the following command:
# install the edge CLI
dart pub global activate edgeThis will give access to the edge command in the terminal (from Dart Edge).
You can use the edge command to create a new project:
edge new supabase_functions new_project
new_projectis the name of the project (name of the folder created by running the command)
Developing a Supabase edge function in dart
Some extra dependencies are required to run functions on the edge:
edge_http_client: for using thehttppackage in Edge environmentssupabase: dart client for Supabase
dependencies:
# Installed when initializing the project
edge: ^0.0.6
supabase_functions: ^0.0.1
# Extra dependencies
supabase: ^1.6.3
edge_http_client: ^0.0.1+1You can add them directly inside pubspec.yaml or by running the following commands:
dart pub add supabase
dart pub add edge_http_clientInitializing Supabase project
The first required step is initializing Supabase by running init:
supabase initNote: Make sure you have the Supabase CLI installed on your device, which gives you access to the
supabasecommand
Running this command will create a new supabase folder in your project containing all the required supabase configurations.
There is more 🤩
Every week I dive headfirst into a topic, uncovering every hidden nook and shadow, to deliver you the most interesting insights
Not convinced? Well, let me tell you more about it
Develop a Supabase function in dart
First make sure you have installed all the dependencies by running pub get:
dart pub getA Supabase function in dart is implemented by using SupabaseFunctions:
import 'package:supabase_functions/supabase_functions.dart';
void main() {
SupabaseFunctions(fetch: (request) async {
/// The function body here 💻
});
}This function gives access to a request object (Request) containing all the information about the incoming request (method, headers, body, and more).
The function then expects you to return a Response. You can use Response.json to return your response as JSON:
import 'package:supabase_functions/supabase_functions.dart';
void main() {
SupabaseFunctions(fetch: (request) async {
return Response.json({ "someParam": "someData" });
});
}The Response class provides also other constructors:
Response.errorResponse.redirect
Finally you can start the application using the edge build command:
edge build supabase_functions --devThis command will compile your Dart code to Javascript (Deno), used to run edge functions in Supabase. You can see the result inside the new supabase/functions/dart_edge folder:
By adding the --dev flag the system will start listening for changes and recompile the code each time.
Make request to Supabase
You can access your Supabase instance by using SupabaseClient (from the supabase package we installed previously):
import 'package:edge_http_client/edge_http_client.dart';
import 'package:supabase/supabase.dart';
import 'package:supabase_functions/supabase_functions.dart';
void main() {
final supabase = SupabaseClient(
Deno.env.get('SUPABASE_URL')!,
/// Use service role key to bypass RLS (Row Level Security)
Deno.env.get('SUPABASE_SERVICE_ROLE_KEY')!,
httpClient: EdgeHttpClient(),
);
SupabaseFunctions(fetch: (request) async {
/// You can query `public.users` table for example
final users = await supabase.from('users').select().limit(10);
return Response.json({
'users': users,
});
});
}Note:
EdgeHttpClientcomes fromedge_http_client, and it is an http client implemented specifically for edge requests
Test your Supabase function locally
The last step is deploying the function on Supabase.
To set up a function locally using Docker, you can use the supabase functions serve command.
Make sure you have Docker installed on your local machine.
Start the Supabase stack by running supabase start:
supabase startThe supabase start command uses Docker to start the Supabase services:
- Postgres database
- Realtime Server
- Supabase API
When you run this command, Docker will pull the necessary images and start the containers. Once all of the Supabase services are running, you will see the output containing your local Supabase credentials.
Note: This command may take a while to run if this is the first time using the CLI, as Docker needs to download the necessary images.
You can use the
supabase stopcommand at any time to stop all services.
You can then deploy and test you function locally by running the following command:
supabase functions serve dart_edge --no-verify-jwtNote: By default Supabase Functions expects a valid auth header (
anon key). The--no-verify-jwtenables you to call the function without a valid auth header
You can now access your Supabase function at http://localhost:54321/functions/v1/dart_edge.
Deploy Supabase Functions remotely
Once you are ready to deploy your function remotely on Supabase first make sure to run the build command:
edge build supabase_functions --devNote: In the current version of
dart_edge(v0.0.6) theedge build supabase_functionscommand does not work (issue on Github). Therefore, to compile your function you need to add the--devflag.
You then need to stop the process that is listening for changes, and finally run the following to deploy on Supabase:
supabase functions deploy dart_edge
dart_edgeis the name of your Supabase function
You will be prompted to insert your project reference id, that you can find in the URL of your Supabase dashboard https://app.supabase.com/project/<your-project-id>, or inside the Project Settings in your dashboard:
You can link your local project to your Supabase instance to avoid having to provide the Supabase reference every time you deploy.
You can now access your function at https://<your-project-id>.functions.supabase.co/dart_edge.
Note: Supabase functions require you to always provide an
Authorizationheader containing an authorization key.Remember to send this header with your request, otherwise you will get a 401 error:
"Missing authorization header"
There is more 🤩
Every week I dive headfirst into a topic, uncovering every hidden nook and shadow, to deliver you the most interesting insights
Not convinced? Well, let me tell you more about it
Packages used to write Supabase Edge functions
As we saw previously, some packages are required to implement and deploy Supabase edge functions in dart. We are now going to see a brief overview of them.
supabase
The supabase package is used to access your Supabase instance.
This package provides all you need to for:
edge_http_client
The edge_http_client package is an http client implemented specifically for edge requests. It is built on top of http and edge_runtime.
It exports a single EdgeHttpClient which extends Client from the http package.
You need to provide EdgeHttpClient as custom client when initializing SupabaseClient:
final supabase = SupabaseClient(
/// `https://<your-project-id>.supabase.co` 👇
Deno.env.get('SUPABASE_URL')!,
/// Anon key 👇
Deno.env.get('SUPABASE_SERVICE_ROLE_KEY')!,
/// Custom http client
httpClient: EdgeHttpClient(),
);
Deno.envprovides access to your Supabase url and key directly as environmental variables once deployed on Supabase
yet_another_json_isolate
We did not install this package directly in this post, but this is another package developed specifically for SupabaseClient (used internally).
yet_another_json_isolate is JSON parsing library that uses isolates to parse JSON.
Isolates in Dart are used to implement concurrent programming: independent workers that are similar to threads but don't share memory, communicating only via messages.
Isolates allow multithreading in Dart: isolates do not share memory with other isolates, instead each new isolate will contain its own memory and event loops.
Two isolates can communicate with each other by passing messages back and forth.
This allow a more efficient JSON parsing implementation.
edge is still an experimental project. You can expect many new features and bug fixes in the next months. Bookmark this post to stay always up to date with the latest additions and upgrades ☑️
You can also follow @SandroMaglione (me 👋) and subscribe to my newsletter here below to receive live updates on Dart, Flutter, Web & Mobile Development 👇
Thanks for reading.
