Skip to content

Build Your First API

This tutorial walks you through building a complete REST API with Fluxbase, from creating your first table to querying data with authentication.

A simple task management API with:

  • A tasks table
  • CRUD operations via REST API
  • User authentication
  • Row-Level Security (RLS) so users only see their own tasks
  • Fluxbase running locally (see Quick Start)
  • Admin account created
  • Node.js installed (for the TypeScript SDK examples)
  1. Open the admin dashboard at http://localhost:8080/admin

  2. Navigate to Tables in the sidebar

  3. Click Create Table

  4. Enter the table details:

    • Name: tasks
    • Schema: public
  5. Add the following columns:

ColumnTypeNullableDefault
iduuidNogen_random_uuid()
user_iduuidNoauth.uid()
titletextNo-
descriptiontextYes-
completedbooleanNofalse
created_attimestamptzNonow()
  1. Click Create Table

Alternatively, run this SQL in the dashboard’s SQL editor:

CREATE TABLE public.tasks (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID NOT NULL DEFAULT auth.uid(),
title TEXT NOT NULL,
description TEXT,
completed BOOLEAN NOT NULL DEFAULT false,
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
-- Create an index for efficient user queries
CREATE INDEX idx_tasks_user_id ON public.tasks(user_id);

Client keys authenticate your application with Fluxbase.

  1. In the dashboard, go to Settings > Client Keys
  2. Click Create Key
  3. Enter:
    • Name: My App
    • Type: Public (for frontend apps) or Service (for backend apps)
  4. Copy the generated key - you’ll need it in the next step

Create a new Node.js project:

Terminal window
mkdir my-fluxbase-app
cd my-fluxbase-app
npm init -y
npm install @fluxbase/sdk

Create a file index.ts:

import { createClient } from '@fluxbase/sdk'
// Replace with your server URL and client key
const fluxbase = createClient(
'http://localhost:8080',
'your-client-key-here'
)
async function main() {
// Test the connection
const { data, error } = await fluxbase.from('tasks').select('*')
if (error) {
console.error('Error:', error.message)
return
}
console.log('Tasks:', data)
}
main()

Run it:

Terminal window
npx tsx index.ts

You should see an empty array [] since we haven’t added any tasks yet.

RLS ensures users can only access their own data.

  1. In the dashboard, go to Tables > tasks
  2. Click the RLS Policies tab
  3. First, enable RLS on the table:
ALTER TABLE public.tasks ENABLE ROW LEVEL SECURITY;
  1. Create policies for each operation:
-- Users can view their own tasks
CREATE POLICY "Users can view own tasks"
ON public.tasks FOR SELECT
USING (auth.uid() = user_id);
-- Users can create their own tasks
CREATE POLICY "Users can create own tasks"
ON public.tasks FOR INSERT
WITH CHECK (auth.uid() = user_id);
-- Users can update their own tasks
CREATE POLICY "Users can update own tasks"
ON public.tasks FOR UPDATE
USING (auth.uid() = user_id);
-- Users can delete their own tasks
CREATE POLICY "Users can delete own tasks"
ON public.tasks FOR DELETE
USING (auth.uid() = user_id);

Enable signups in the dashboard:

  1. Go to Settings > Authentication
  2. Enable Allow Signups
  3. Save changes

Update your index.ts to sign up a user:

import { createClient } from '@fluxbase/sdk'
const fluxbase = createClient(
'http://localhost:8080',
'your-client-key-here'
)
async function main() {
// Sign up a new user
const { data: authData, error: authError } = await fluxbase.auth.signUp({
email: 'user@example.com',
password: 'securepassword123'
})
if (authError) {
console.error('Auth error:', authError.message)
return
}
console.log('User created:', authData.user?.email)
console.log('Access token:', authData.access_token)
}
main()

Run it to create the user.

Now let’s build a complete example:

import { createClient } from '@fluxbase/sdk'
const fluxbase = createClient(
'http://localhost:8080',
'your-client-key-here'
)
async function main() {
// Sign in
const { data: auth, error: authError } = await fluxbase.auth.signIn({
email: 'user@example.com',
password: 'securepassword123'
})
if (authError) {
console.error('Login failed:', authError.message)
return
}
console.log('Logged in as:', auth.user?.email)
// Create a task
const { data: newTask, error: createError } = await fluxbase
.from('tasks')
.insert({
title: 'Learn Fluxbase',
description: 'Complete the first API tutorial'
})
.select()
.single()
if (createError) {
console.error('Create error:', createError.message)
return
}
console.log('Created task:', newTask)
// List all tasks
const { data: tasks, error: listError } = await fluxbase
.from('tasks')
.select('*')
.order('created_at', { ascending: false })
if (listError) {
console.error('List error:', listError.message)
return
}
console.log('All tasks:', tasks)
// Update a task
const { data: updated, error: updateError } = await fluxbase
.from('tasks')
.update({ completed: true })
.eq('id', newTask.id)
.select()
.single()
if (updateError) {
console.error('Update error:', updateError.message)
return
}
console.log('Updated task:', updated)
// Delete a task
const { error: deleteError } = await fluxbase
.from('tasks')
.delete()
.eq('id', newTask.id)
if (deleteError) {
console.error('Delete error:', deleteError.message)
} else {
console.log('Task deleted')
}
}
main()

You can also use the REST API directly:

Terminal window
# Get an access token
TOKEN=$(curl -s -X POST http://localhost:8080/auth/v1/token \
-H "Content-Type: application/json" \
-H "X-Client-Key: your-client-key-here" \
-d '{"email":"user@example.com","password":"securepassword123","grant_type":"password"}' \
| jq -r '.access_token')
# Create a task
curl -X POST http://localhost:8080/api/v1/tables/public/tasks \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"title":"My first task","description":"Created via REST API"}'
# List tasks
curl http://localhost:8080/api/v1/tables/public/tasks \
-H "Authorization: Bearer $TOKEN"
# Filter tasks
curl "http://localhost:8080/api/v1/tables/public/tasks?completed=eq.false" \
-H "Authorization: Bearer $TOKEN"

The REST API supports PostgREST-compatible operators:

OperatorDescriptionExample
eqEqual?status=eq.active
neqNot equal?status=neq.deleted
gtGreater than?created_at=gt.2024-01-01
gteGreater or equal?priority=gte.5
ltLess than?priority=lt.3
lteLess or equal?priority=lte.10
likePattern match?title=like.*urgent*
ilikeCase-insensitive pattern?title=ilike.*URGENT*
inIn list?status=in.(active,pending)
isIs null/true/false?deleted_at=is.null
// Filter by column value
const { data } = await fluxbase
.from('tasks')
.select('*')
.eq('completed', false)
// Multiple filters (AND)
const { data } = await fluxbase
.from('tasks')
.select('*')
.eq('completed', false)
.gte('priority', 5)
// Order and limit
const { data } = await fluxbase
.from('tasks')
.select('*')
.order('created_at', { ascending: false })
.limit(10)
// Select specific columns
const { data } = await fluxbase
.from('tasks')
.select('id, title, completed')
// Count rows
const { count } = await fluxbase
.from('tasks')
.select('*', { count: 'exact', head: true })

Congratulations! You’ve built your first Fluxbase API. Here’s what to explore next: