Supabase With TypeScript: A Developer's Guide

by Jhon Lennon 46 views

Hey guys! Today, we're diving deep into the world of Supabase and TypeScript. If you're looking to build scalable, type-safe applications, then you've come to the right place. We'll explore how to leverage the power of Supabase as a backend with the robustness of TypeScript on the frontend. Let's get started!

Why Supabase and TypeScript?

Supabase: The Open Source Firebase Alternative

Supabase is often referred to as the open-source alternative to Firebase. It provides a suite of tools to help you build backends quickly. Think of it as a comprehensive backend-as-a-service (BaaS) platform. Here’s what makes Supabase so appealing:

  • Realtime Database: Supabase uses PostgreSQL, a powerful and reliable relational database. With its realtime capabilities, your app can react instantly to data changes.
  • Authentication: Supabase offers built-in authentication, making it easy to manage users with various providers like Google, GitHub, and more. You can also implement custom authentication flows.
  • Storage: Storing and serving files is a breeze with Supabase's storage solution, which is built on top of Google Cloud Storage. It’s secure, scalable, and easy to use.
  • Functions: Supabase allows you to deploy serverless functions written in JavaScript or TypeScript, enabling you to extend your backend logic without managing servers.

The beauty of Supabase lies in its simplicity and the fact that it's built on open standards. You're not locked into a proprietary ecosystem, giving you more control and flexibility over your data and infrastructure.

TypeScript: Adding Type Safety to JavaScript

TypeScript is a superset of JavaScript that adds static typing. This means you can catch errors during development rather than at runtime. For larger projects, this can be a game-changer. Here’s why TypeScript is awesome:

  • Early Error Detection: TypeScript's static typing allows you to catch type-related errors during development, reducing the likelihood of runtime bugs.
  • Improved Code Maintainability: With explicit types, your code becomes more self-documenting, making it easier to understand and maintain.
  • Enhanced Code Completion: IDEs can provide better code completion and suggestions with TypeScript, improving your development workflow.
  • Refactoring Support: Refactoring becomes safer and easier because TypeScript can help you identify all the places where a type change might have an impact.

TypeScript makes JavaScript development more robust and scalable, especially for complex applications. By using TypeScript, you can write more maintainable and reliable code.

The Synergy

Combining Supabase and TypeScript gives you the best of both worlds: a powerful, easy-to-use backend with a robust, type-safe frontend. This combination helps you build scalable, maintainable, and reliable applications. Using TypeScript with Supabase enhances the development experience by providing type safety across your entire stack.

Setting Up Your Project

Prerequisites

Before we dive into the code, make sure you have the following installed:

  • Node.js: You'll need Node.js to run your TypeScript project.
  • npm or Yarn: A package manager to install dependencies.
  • Supabase Account: Sign up for a free Supabase account at supabase.com.

Creating a Supabase Project

  1. Sign In: Log in to your Supabase account.
  2. New Project: Click on "New Project" and provide the necessary details (name, region, database password).
  3. Database Details: Once your project is created, you'll find your project URL and API key in the project settings. You'll need these to connect to your Supabase backend.

Initializing a TypeScript Project

Let's create a new TypeScript project:

mkdir supabase-typescript-app
cd supabase-typescript-app
npm init -y
tsc --init

This will create a package.json file and a tsconfig.json file, which configures the TypeScript compiler. Open tsconfig.json and configure it as follows:

{
  "compilerOptions": {
    "target": "es2020",
    "module": "esnext",
    "moduleResolution": "node",
    "esModuleInterop": true,
    "forceConsistentCasingInFileNames": true,
    "strict": true,
    "skipLibCheck": true,
    "outDir": "dist"
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules"]
}

Installing Supabase Client

Next, install the Supabase client library:

npm install @supabase/supabase-js
npm install typescript @types/node -D

The @supabase/supabase-js package is the official Supabase client library for JavaScript and TypeScript. The other packages are TypeScript itself and type definitions for Node.js.

Connecting to Supabase

Setting Up the Client

Create a new directory named src and add a file named supabaseClient.ts:

mkdir src
touch src/supabaseClient.ts

Open src/supabaseClient.ts and add the following code:

import { createClient } from '@supabase/supabase-js';

const supabaseUrl = process.env.SUPABASE_URL || '';
const supabaseKey = process.env.SUPABASE_ANON_KEY || '';

export const supabase = createClient(supabaseUrl, supabaseKey);

Important: Store your SUPABASE_URL and SUPABASE_ANON_KEY in environment variables to keep them secure. You can set these variables in your .env file. Make sure to install the dotenv package:

npm install dotenv

Create a .env file in the root of your project:

SUPABASE_URL=your_supabase_url
SUPABASE_ANON_KEY=your_supabase_anon_key

And update your supabaseClient.ts to load the environment variables:

import { createClient } from '@supabase/supabase-js';
import * as dotenv from 'dotenv';

dotenv.config();

const supabaseUrl = process.env.SUPABASE_URL || '';
const supabaseKey = process.env.SUPABASE_ANON_KEY || '';

export const supabase = createClient(supabaseUrl, supabaseKey);

Performing CRUD Operations

Now that we have our Supabase client set up, let's perform some basic CRUD (Create, Read, Update, Delete) operations.

Creating Data

Let’s create a new file called src/create.ts to handle creating data:

touch src/create.ts

Add the following code:

import { supabase } from './supabaseClient';

async function createRecord() {
  const { data, error } = await supabase
    .from('your_table_name')
    .insert([
      {
        column1: 'value1',
        column2: 'value2',
      },
    ]);

  if (error) {
    console.error('Error inserting data:', error);
  } else {
    console.log('Data inserted successfully:', data);
  }
}

createRecord();

Replace your_table_name, column1, column2, value1, and value2 with your actual table and column names and desired values.

Reading Data

Create a new file called src/read.ts:

touch src/read.ts

Add the following code:

import { supabase } from './supabaseClient';

async function readRecords() {
  const { data, error } = await supabase
    .from('your_table_name')
    .select('*');

  if (error) {
    console.error('Error reading data:', error);
  } else {
    console.log('Data read successfully:', data);
  }
}

readRecords();

Replace your_table_name with the name of your table.

Updating Data

Create a new file called src/update.ts:

touch src/update.ts

Add the following code:

import { supabase } from './supabaseClient';

async function updateRecord() {
  const { data, error } = await supabase
    .from('your_table_name')
    .update({
      column1: 'new_value1',
      column2: 'new_value2',
    })
    .eq('id', 1); // Replace 1 with the ID of the record you want to update

  if (error) {
    console.error('Error updating data:', error);
  } else {
    console.log('Data updated successfully:', data);
  }
}

updateRecord();

Replace your_table_name, column1, column2, new_value1, and new_value2 with your actual table and column names and desired values. Also, replace 1 with the ID of the record you want to update.

Deleting Data

Create a new file called src/delete.ts:

touch src/delete.ts

Add the following code:

import { supabase } from './supabaseClient';

async function deleteRecord() {
  const { data, error } = await supabase
    .from('your_table_name')
    .delete()
    .eq('id', 1); // Replace 1 with the ID of the record you want to delete

  if (error) {
    console.error('Error deleting data:', error);
  } else {
    console.log('Data deleted successfully:', data);
  }
}

deleteRecord();

Replace your_table_name with the name of your table. Also, replace 1 with the ID of the record you want to delete.

Running the Code

To run these scripts, add the following to your package.json file under the scripts section:

  "scripts": {
    "create": "ts-node src/create.ts",
    "read": "ts-node src/read.ts",
    "update": "ts-node src/update.ts",
    "delete": "ts-node src/delete.ts"
  },

Now you can run these scripts using npm run create, npm run read, npm run update, and npm run delete.

Authentication with Supabase and TypeScript

Setting Up Authentication

Supabase provides built-in authentication. Let's see how to use it with TypeScript.

Create a new file called src/auth.ts:

touch src/auth.ts

Add the following code:

import { supabase } from './supabaseClient';

async function signUp(email: string, password: string) {
  const { data, error } = await supabase.auth.signUp({
    email: email,
    password: password,
  });

  if (error) {
    console.error('Error signing up:', error);
  } else {
    console.log('Signed up successfully:', data);
  }
}

async function signIn(email: string, password: string) {
  const { data, error } = await supabase.auth.signInWithPassword({
    email: email,
    password: password,
  });

  if (error) {
    console.error('Error signing in:', error);
  } else {
    console.log('Signed in successfully:', data);
  }
}

async function signOut() {
  const { error } = await supabase.auth.signOut();

  if (error) {
    console.error('Error signing out:', error);
  } else {
    console.log('Signed out successfully');
  }
}

// Example usage:
// signUp('test@example.com', 'password123');
// signIn('test@example.com', 'password123');
// signOut();

Handling User Sessions

To manage user sessions, you can use the supabase.auth.getSession() method.

async function getSession() {
  const { data: { session }, error } = await supabase.auth.getSession()

  if (error) {
    console.error('Error getting session:', error);
  } else {
    console.log('Session:', session);
  }
}

getSession();

Realtime Subscriptions

Supabase’s realtime capabilities allow you to subscribe to changes in your database.

Create a new file called src/realtime.ts:

touch src/realtime.ts

Add the following code:

import { supabase } from './supabaseClient';

supabase
  .channel('any')
  .on(
    'postgres_changes',
    { event: '*', schema: 'public', table: 'your_table_name' },
    (payload) => {
      console.log('Change received!', payload);
    }
  )
  .subscribe();

Replace your_table_name with the name of your table. This code subscribes to all changes (inserts, updates, deletes) on the specified table.

Conclusion

Alright, guys, we've covered a lot! You now have a solid foundation for building applications with Supabase and TypeScript. From setting up your project and performing CRUD operations to handling authentication and using realtime subscriptions, you’re well-equipped to create scalable and type-safe applications. Keep experimenting, keep building, and happy coding!

By leveraging the power of Supabase and TypeScript, you can create robust, maintainable, and scalable applications. The combination of a powerful backend-as-a-service with the type safety of TypeScript enhances the development experience and helps you build better software.