Section

Writing Your First API Endpoint: Fetching Data with Functions

Part of The Prince Academy's AI & DX engineering stack.

Follow The Prince Academy Inc.

One of the most common tasks when building web applications is fetching data. Supabase Functions allow you to write serverless functions that can interact with your database and expose this data through API endpoints. In this section, we'll guide you through creating your very first API endpoint to fetch data from your Supabase project.

Let's imagine we have a simple table called todos in our Supabase database with columns like id, task, and is_complete. Our goal is to create a function that, when called via an HTTP request, returns all the tasks from this table.

First, you'll need to navigate to the 'Edge Functions' section in your Supabase project dashboard. From there, click on 'New Function' to start creating a new function. You'll be prompted to give your function a name. Let's call it get-todos.

Supabase provides a pre-written boilerplate for new functions. We'll modify this to fetch our data. The core of our function will be written in JavaScript (or TypeScript if you prefer). Here's how the get-todos function might look:

import { serve } from 'https://deno.land/std@0.168.0/http/server.ts'
import { corsHeaders } from './_shared/cors.ts'

// Supabase client setup (assuming you have your SUPABASE_URL and SUPABASE_ANON_KEY set as environment variables)
import { createClient } from '@supabase/supabase-js'

const supabase = createClient(Deno.env.get('SUPABASE_URL')!, Deno.env.get('SUPABASE_ANON_KEY')!)

serve(async (req) => {
  // Check if it's a CORS preflight request
  if (req.method === 'OPTIONS') {
    return new Response('OK', { headers: corsHeaders })
  }

  // This is where the magic happens: fetching data from Supabase
  try {
    const { data, error } = await supabase
      .from('todos')
      .select('*') // Select all columns

    if (error) {
      throw error
    }

    // Return the fetched data as a JSON response
    return new Response(JSON.stringify(data), {
      headers: {
        ...corsHeaders,
        'Content-Type': 'application/json',
      },
    })
  } catch (error) {
    return new Response(JSON.stringify({ error: error.message }), {
      headers: {
        ...corsHeaders,
        'Content-Type': 'application/json',
      },
      status: 500, // Internal Server Error
    })
  }
})

Let's break down the key parts of this code:

  • Importing Dependencies: We import serve from Deno's standard library for handling HTTP requests and corsHeaders for Cross-Origin Resource Sharing. Crucially, we also import createClient from the Supabase JS library to interact with our database.
  • Supabase Client Initialization: We create an instance of the Supabase client using your project's URL and anonymous key, which are securely stored as environment variables in your Supabase Function's configuration.
  • Handling Requests: The serve function takes a callback that receives the incoming request (req). We first check for an OPTIONS request, which is part of the CORS preflight process, and respond accordingly.
  • Fetching Data: This is the core logic. supabase.from('todos').select('*') tells Supabase to query the todos table and fetch all columns (*). The await keyword ensures we wait for the database operation to complete.
  • Error Handling: We check for any error returned from the Supabase query and throw it if present. This allows us to catch and report potential issues.
  • Returning JSON Response: If the data is fetched successfully, we stringify the data and return it as a JSON response with the appropriate headers, including CORS headers and Content-Type: application/json.
  • Catching Errors: The try...catch block ensures that any errors during the process are caught, and an informative JSON error message is returned to the client with a 500 status code.

After writing your function code, you'll need to deploy it. Supabase provides a CLI tool for this, or you can deploy directly from the dashboard. Once deployed, your function will be accessible via a unique URL. You can then make a GET request to this URL from your frontend application or any other client to retrieve the list of todos.

graph TD;
    User_Request(HTTP GET Request to /api/get-todos) --> Supabase_Function(Supabase Edge Function: get-todos);
    Supabase_Function --> Supabase_DB(Supabase Database: Query 'todos' table);
    Supabase_DB --> Supabase_Function(Return data to function);
    Supabase_Function --> User_Response(JSON Response with todo list);

This simple example demonstrates the power of Supabase Functions in creating custom API endpoints. You can extend this pattern to perform more complex operations, interact with other services, and build robust APIs tailored to your application's needs.