Last time, we had a brief look on BaaS (Backend as a Service). So, today, i'd like to introduce Supabase as a BaaS example. If you go to their site, you'll see a banner that said:
"Build in a weekend.
Scale to millions"
They actually mean it. I'm not very sure about the "scale to millions" part, but it's definitely doable building something over the weekend with Supabase.
Features or "Products" (as Supabase call in their documents) include Database, Authentication, Storage, AI & Vectors, Realtime and Edge Functions.
Since it's an overview, i'm not going to go through all of them, and only focus on the aspects that all backends need, which are API, database and authentication. But don't worry, their docs are well written and clear, if you need to implement other features, check out their official document.
Using BaaS means that you have no backend code to maintain, instead, everything is in a dashboard, from adding table to setting up security.
1. Database
Every Supabase project comes with a full Postgres database, a free and open source database which is considered one of the world's most stable and advanced databases.
Each table in database is stored as a form of spreasheet so it's easy to use, to edit, even to adjust relationship between tables.
Supabase allows us to enable Row-level security (RLS, a type of security that lets you filter data and enables access to specific rows in a table based on qualifying user conditions) with a click.
2. API
Supabase provides a RESTful API using PostgREST. This is a very thin API layer on top of Postgres. It exposes everything you need from a CRUD API at the URL.
API docs is auto-generated for each table, and types can be generated with Supabase CLI or again, with a click.
3. Authentication and Authorization
Supabase allows you to authenticate in various ways:
Then, we can authorize users with row-level security.
As always, i'll use NextJs as an example but you can get a quick start with your favorite framework and language.
Learn More โ
Learn More โ
1. Setting up
npx create-next-app -e with-supabase
npm install @supabase/supabase-js @supabase/ssr
** Make sure to have client.ts
, server.ts
, middleware.ts
files in your /src/utils/supabase
folder. Content of these files can be refered here. And also route.ts
file in your src/app/auth/callback
folder as below.
import { createClient } from "@/utils/supabase/server";
import { NextResponse } from "next/server";
export async function GET(request: Request) {
// The `/auth/callback` route is required for the server-side auth flow implemented
// by the SSR package. It exchanges an auth code for the user's session.
// https://supabase.com/docs/guides/auth/server-side/nextjs
const requestUrl = new URL(request.url);
const code = requestUrl.searchParams.get("code");
const origin = requestUrl.origin;
if (code) {
const supabase = createClient();
await supabase.auth.exchangeCodeForSession(code);
}
// URL to redirect to after sign up process completes
return NextResponse.redirect(`${origin}/protected`);
}
.local.env
to your project NEXT_PUBLIC_SUPABASE_URL=<SUBSTITUTE_SUPABASE_URL>
NEXT_PUBLIC_SUPABASE_ANON_KEY=<SUBSTITUTE_SUPABASE_ANON_KEY>
SUBSTITUTE_SUPABASE_URL
is your project URL, and SUBSTITUTE_SUPABASE_ANON_KEY
is project API key. You can find them in Project setting > API section
2. Database
We can create new tables and datas using "Table Editor" (manually add table, colums and datas) and "SQL Editor" (normal SQL scripts).
Since we haven't implemented authorization, be sure that RLS is disabled.
3. API
Head over to API Docs
on your Dashboard side menu.
In Tables and Views
section, you will see all your table there, select a table and you'll find api docs that help you query data from that selected table.
To generate types and download types, select Introduction
and click on generate button.
Basic CRUD operation works perfectly fine, and we can also listen to changes of database. But in case you have a complex query case, you can add your own query functions using Query Editor, or go to Database and add your functions. Then go back to API Docs
, you'll see your new function's doc under Stored Procedures
section.
To use API with type in your project is simple, here's an example of getting all notes from Note database that we created at earlier.
"use client";
import { Tables } from "@/app/types/supabase";
import { createClient } from "@/utils/supabase/client";
import { useState } from "react";
export default function Test() {
const supabase = createClient();
const [notes, setNotes] = useState<Tables<"notes">[]>([]);
supabase
.from("notes")
.select()
.then((res) => res.data && setNotes(res.data));
return (
<div>
Notes:<br /><br />
<ul>
{notes.map((n, nId) => (
<li key={nId}>{n.id}. {n.title}</li>
))}
</ul>
</div>
);
}
Output:
*Please be noted that if your component is server side render, createClient
should be imported from @/utils/supabase/server
Just follow the API Docs
to get, post, update, delete, subsctibe to changes, and to call your custom query functions.
If you get any error, recheck your .env
and RLS status of your table.
4. Authentication and Authorization
Authentication should normally be implemented first, but this part is easy with Supabase, so it's doesn't matter much.
Navigating to Authentication > Providers, you will see that email has been enable by default, but there are also other Auth Providers that you can enable.
The API for signup looks like this:
// this is example on SSR. API on CSR is similar
const signUp = async (formData: FormData) => {
const origin = headers().get("origin");
const email = formData.get("email") as string;
const password = formData.get("password") as string;
const supabase = createClient();
const { error } = await supabase.auth.signUp({
email,
password,
options: {
emailRedirectTo: `${origin}/auth/callback`,
},
});
if (error) {
return redirect("/login?message=Could not authenticate user");
}
return redirect("/login?message=Check email to continue sign in process");
};
The signup flow is nothing far from normal:
code
, which redirect user to page /auth/callback and code will be checked to make sure it's the correct userAfter successfully registered, next login will be a simple api call.
// this is example on SSR. API on CSR is similar
const signIn = async (formData: FormData) => {
"use server";
const email = formData.get("email") as string;
const password = formData.get("password") as string;
const supabase = createClient();
const { error } = await supabase.auth.signInWithPassword({
email,
password,
});
if (error) {
return redirect("/login?message=Could not authenticate user");
}
return redirect("/protected");
};
When logging out, we also need to call api.
// this is example on SSR. API on CSR is similar
const signOut = async () => {
"use server";
const supabase = createClient();
await supabase.auth.signOut();
return redirect("/login");
};
Et, voilร !
Your app is done, just deploy your frontend and replace your domain on supabase with your deployed domain, and you app is good to go
I guess now you know why their banner said "Build in a weekend". Above are enough to build an app, but there are a lot more, if you have a chance, i believe it's worth a try. Thank you for reading this far. Hope to see you in another blog.