SDK Connection Guide
This guide shows how to connect to your self-hosted WoWSQL instance from JavaScript, Python, and other languages using the WoWSQL SDK or raw HTTP.
Getting Your Credentials
You need two values to connect:
- API URL — The Kong gateway address (default:
http://localhost:8080) - Anon Key — The public API key with the
anonrole
Both are available in the dashboard under Settings. The anon key is a JWT that looks like:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoiYW5vbi...
JavaScript / TypeScript
Install
npm install @wowsql/sdk-js
Initialize
import { createClient } from '@wowsql/sdk-js'
const wowsql = createClient(
'http://localhost:8080', // Your API URL
'YOUR_ANON_KEY' // From Settings page
)
Query data
// Select all rows
const { data, error } = await wowsql
.from('todos')
.select('*')
// Insert a row
const { data, error } = await wowsql
.from('todos')
.insert({ title: 'Buy groceries', completed: false })
// Update
const { data, error } = await wowsql
.from('todos')
.update({ completed: true })
.eq('id', 1)
// Delete
const { error } = await wowsql
.from('todos')
.delete()
.eq('id', 1)
Authentication
// Sign up a new user
const { data, error } = await wowsql.auth.signUp({
email: 'user@example.com',
password: 'secure-password'
})
// Sign in
const { data, error } = await wowsql.auth.signInWithPassword({
email: 'user@example.com',
password: 'secure-password'
})
// Get current user
const { data: { user } } = await wowsql.auth.getUser()
// Sign out
await wowsql.auth.signOut()
Realtime subscriptions
const channel = wowsql
.channel('todos-changes')
.on('postgres_changes',
{ event: '*', schema: 'public', table: 'todos' },
(payload) => {
console.log('Change:', payload)
}
)
.subscribe()
Storage
// Upload a file
const { data, error } = await wowsql.storage
.from('avatars')
.upload('user1.png', file)
// Get public URL
const { data } = wowsql.storage
.from('avatars')
.getPublicUrl('user1.png')
Python
Install
pip install wowsql
Initialize
from wowsql import create_client
client = create_client(
"http://localhost:8080", # Your API URL
"YOUR_ANON_KEY" # From Settings page
)
Query data
# Select
response = client.table("todos").select("*").execute()
print(response.data)
# Insert
response = client.table("todos").insert({
"title": "Buy groceries",
"completed": False
}).execute()
# Update
response = client.table("todos").update({
"completed": True
}).eq("id", 1).execute()
# Delete
response = client.table("todos").delete().eq("id", 1).execute()
Authentication
# Sign up
response = client.auth.sign_up({
"email": "user@example.com",
"password": "secure-password"
})
# Sign in
response = client.auth.sign_in_with_password({
"email": "user@example.com",
"password": "secure-password"
})
Raw HTTP (cURL)
You can use any HTTP client. Pass the anon key in both headers:
Read data
curl 'http://localhost:8080/rest/v1/todos?select=*' \
-H "apikey: YOUR_ANON_KEY" \
-H "Authorization: Bearer YOUR_ANON_KEY"
Insert data
curl 'http://localhost:8080/rest/v1/todos' \
-X POST \
-H "apikey: YOUR_ANON_KEY" \
-H "Authorization: Bearer YOUR_ANON_KEY" \
-H "Content-Type: application/json" \
-H "Prefer: return=representation" \
-d '{"title": "Buy groceries", "completed": false}'
Filter and paginate
# Filter: completed = true
curl 'http://localhost:8080/rest/v1/todos?completed=eq.true' \
-H "apikey: YOUR_ANON_KEY" \
-H "Authorization: Bearer YOUR_ANON_KEY"
# Paginate: 10 items starting from offset 20
curl 'http://localhost:8080/rest/v1/todos?select=*&limit=10&offset=20' \
-H "apikey: YOUR_ANON_KEY" \
-H "Authorization: Bearer YOUR_ANON_KEY"
# Order by created_at descending
curl 'http://localhost:8080/rest/v1/todos?order=created_at.desc' \
-H "apikey: YOUR_ANON_KEY" \
-H "Authorization: Bearer YOUR_ANON_KEY"
Authenticate a user
# Sign up
curl 'http://localhost:8080/auth/v1/signup' \
-X POST \
-H "apikey: YOUR_ANON_KEY" \
-H "Content-Type: application/json" \
-d '{"email": "user@example.com", "password": "securepass"}'
# Sign in (returns access_token)
curl 'http://localhost:8080/auth/v1/token?grant_type=password' \
-X POST \
-H "apikey: YOUR_ANON_KEY" \
-H "Content-Type: application/json" \
-d '{"email": "user@example.com", "password": "securepass"}'
Use authenticated token
After signing in, use the returned access_token in subsequent requests:
curl 'http://localhost:8080/rest/v1/todos' \
-H "apikey: YOUR_ANON_KEY" \
-H "Authorization: Bearer USER_ACCESS_TOKEN"
Note: The
apikey header always uses the anon key. The Authorization header uses the user's access token after login. This tells PostgREST to execute queries as the authenticated role.Using the Service Role Key
The service role key bypasses Row Level Security. Use it only in server-side code (backend APIs, scripts, admin tools).
// Server-side only
const admin = createClient(
'http://localhost:8080',
'YOUR_SERVICE_ROLE_KEY'
)
// This bypasses all RLS policies
const { data } = await admin
.from('todos')
.select('*')
Never expose the service role key in client-side code. It grants unrestricted access to all data in your database.
Row Level Security Basics
After creating a table, enable RLS and write policies to control access:
-- Enable RLS on the table
ALTER TABLE public.todos ENABLE ROW LEVEL SECURITY;
-- Allow anyone to read all todos
CREATE POLICY "Public read access"
ON public.todos FOR SELECT
USING (true);
-- Only the owner can insert
CREATE POLICY "Users insert own todos"
ON public.todos FOR INSERT
WITH CHECK (auth.uid() = user_id);
-- Only the owner can update
CREATE POLICY "Users update own todos"
ON public.todos FOR UPDATE
USING (auth.uid() = user_id);
-- Only the owner can delete
CREATE POLICY "Users delete own todos"
ON public.todos FOR DELETE
USING (auth.uid() = user_id);
Tip: Without RLS policies, a table with RLS enabled returns empty results for the anon and authenticated roles. Always create at least a SELECT policy.