Fetching data from Supabase
Learn how fetch data from your Supabase database in Makerkit and Next.js
When fetching data from the Supabase Postgres Database, we use the Supabase JS client.
To make data-fetching from Supabase more reusable, our convention is to create client-agnostic functions that receive a Supabase client as a parameter. Then, we can use these functions in both the browser and the server by injecting in the appropriate client.
For example, let's take a look at the hook to fetch an organization from Supabase.
First, we want to write a query that receives two parameters:
- a Supabase client interface
- an organization ID
export function getOrganizationById( client: Client, organizationId: number) { return client .from('organizations') .select(` id, name, logoURL: logo_url `) .eq('id', organizationId) .throwOnError() .single();}
It's important that we pass the client as a parameter so that we can use the function in both the browser and the server.
There are two ways to use this function:
- Server: directly, in a server-side function such as: a Route Handler, a Server Action, a Server Component, or a Middleware
- Client: indirectly, in a React Hook in a client-side component
Retrieving data in a server-side function
Let's see some scenarios where we can use this function in a server-side.
Route Handler
When you are fetching data from a Route Handler, you can use the getSupabaseRouteHandlerClient
function.
import { getOrganizationById } from '~/lib/organizations/database/queries';import getSupabaseRouteHandlerClient from '~/core/supabase/route-handler-client';import { NextRequest, NextResponse } from "next/server";export const GET = async ( req: NextRequest, { params }: { params: { id: string } }) => { const client = getSupabaseRouteHandlerClient(); const { data } = await getOrganizationById(client, params.id); return NextResponse.json(data);};
Server Action
When you are performing mutations using React Server Actions, you can use the getSupabaseServerActionClient
function to read data from the Supabase database.
'use server';import getSupabaseServerActionClient from '~/core/supabase/action-client';import { getOrganizationById } from '~/lib/organizations/database/queries';export async function getOrganizationByIdAction( organizationId: number) { const client = getSupabaseServerActionClient(); const { data } = await getOrganizationById(client, organizationId); return data;}
Server Component
When you are fetching data from a Server Component, you can use the getSupabaseServerComponentClient
function.
import getSupabaseServerComponentClient from '~/core/supabase/server-component-client';import { getOrganizationById } from '~/lib/organizations/database/queries';interface Params { params: { id: string; };}async function OrganizationPage({ params }: Params) { const client = getSupabaseServerComponentClient(); const organization = await getOrganizationById(client, params.id); return <div>{organization.name}</div>;}
Retrieving data in a client-side function
Now, if we want to use a React Hook to fetch the organization from one of our components, we can use the useSWR
hook from swr
:
import useSupabase from '~/core/hooks/use-supabase';import { getOrganizationById } from '~/lib/organizations/database/queries';import useSWR from 'swr';function useOrganizationQuery( organizationId: number) { const client = useSupabase(); const key = ['organization', organizationId]; return useSWR(key, async () => { return getOrganizationById(client, organizationId).then( (result) => result.data ); });}export default useOrganizationQuery;
Retrieving data using a React hook
Now that we have a hook to fetch an organization, we can use it in our components to retrieve the data.
import { useOrganizationQuery } from './use-organization-query';function OrganizationCard({ organizationId }) { const { data: organization, isLoading, error } = useOrganizationQuery(organizationId); /* data is loading */ if (isLoading) { return <div>Loading...</div> } /* request errored */ if (error) { return <div>Error!</div> } /* request successful, we can access "organization" */ return <div>{organization.name}</div>;}