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 edge
This 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_project
is 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 thehttp
package 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+1
You can add them directly inside pubspec.yaml
or by running the following commands:
dart pub add supabase
dart pub add edge_http_client
Initializing Supabase project
The first required step is initializing Supabase by running init
:
supabase init
Note: Make sure you have the Supabase CLI installed on your device, which gives you access to the
supabase
command
Running this command will create a new supabase
folder in your project containing all the required supabase configurations.
There is more π€©
Timeless coding principles, practices, and tools that make a difference, regardless of your language or framework, delivered in your inbox every week.
Develop a Supabase function in dart
First make sure you have installed all the dependencies by running pub get
:
dart pub get
A 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.error
Response.redirect
Finally you can start the application using the edge build
command:
edge build supabase_functions --dev
This 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:
EdgeHttpClient
comes 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 start
The 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 stop
command 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-jwt
Note: By default Supabase Functions expects a valid auth header (
anon key
). The--no-verify-jwt
enables 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 --dev
Note: In the current version of
dart_edge
(v0.0.6) theedge build supabase_functions
command does not work (issue on Github). Therefore, to compile your function you need to add the--dev
flag.
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_edge
is 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
Authorization
header 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 π€©
Timeless coding principles, practices, and tools that make a difference, regardless of your language or framework, delivered in your inbox every week.
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.env
provides 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.