Connect Your Frontend

This page gives you a drop-in API client and copy-paste examples for sign-up, login, and CRUD.

Using a coding agent?

API client

Put this in src/lib/api.js or src/lib/api.ts. It handles auth headers, token refresh on 401, and JSON parsing.

js
export const API = 'http://localhost:8787/api/v1'

export const session = {
  token: '',
  refreshToken: '',
  userId: '',
}

export function setSession(payload) {
  session.token = payload.token
  session.refreshToken = payload.refresh_token
  session.userId = payload.record?.id || ''
}

export function clearSession() {
  session.token = ''
  session.refreshToken = ''
  session.userId = ''
}

async function readBody(res) {
  const text = await res.text()
  try {
    return text ? JSON.parse(text) : null
  } catch {
    return text
  }
}

export async function refreshSession() {
  if (!session.token || !session.refreshToken) {
    throw new Error('No session to refresh')
  }

  const res = await fetch(`${API}/table/users/auth/refresh-token`, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      Authorization: `Bearer ${session.token}`,
    },
    body: JSON.stringify({
      refresh_token: session.refreshToken,
    }),
  })

  const data = await readBody(res)
  if (!res.ok) {
    throw new Error(typeof data === 'string' ? data : JSON.stringify(data))
  }

  setSession(data)
  return data
}

export async function request(path, { method = 'GET', body, auth = true, retry = true } = {}) {
  const res = await fetch(`${API}${path}`, {
    method,
    headers: {
      ...(body ? { 'Content-Type': 'application/json' } : {}),
      ...(auth && session.token ? { Authorization: `Bearer ${session.token}` } : {}),
    },
    body: body ? JSON.stringify(body) : undefined,
  })

  if (res.status === 401 && auth && retry && session.refreshToken) {
    await refreshSession()
    return request(path, { method, body, auth, retry: false })
  }

  const data = await readBody(res)
  if (!res.ok) {
    throw new Error(typeof data === 'string' ? data : JSON.stringify(data))
  }

  return data
}

export async function signUp(values) {
  const data = await request('/table/users/auth/sign-up', {
    method: 'POST',
    auth: false,
    body: values,
  })
  setSession(data)
  return data
}

export async function login(identity, password) {
  const data = await request('/table/users/auth/login-password', {
    method: 'POST',
    auth: false,
    body: { identity, password },
  })
  setSession(data)
  return data
}

export async function logout() {
  await request('/table/users/auth/logout', {
    method: 'POST',
  })
  clearSession()
}

Sign up

With the default scaffold, name and passwordConfirm are required.

js
import { signUp } from './lib/api.js'

const session = await signUp({
  username: 'alice',
  email: 'alice@example.com',
  password: 'secret123',
  passwordConfirm: 'secret123',
  name: 'Alice',
})

console.log(session.record.id)

Log in

js
import { login } from './lib/api.js'

await login('alice@example.com', 'secret123')

identity accepts either email or username.

Protected requests

js
import { request } from './lib/api.js'

const me = await request('/table/users/select?limit=1')
console.log(me)

The client sends Authorization: Bearer <token> automatically.

CRUD

Read public posts

js
import { request } from './lib/api.js'

const posts = await request('/table/posts/select?where=published==true&order=-created&limit=20', {
  auth: false,
})

Create a post

If your rule is createRule: 'auth.uid == author', the insert must include the signed-in user's ID as author.

js
import { request, session } from './lib/api.js'

const created = await request('/table/posts/insert', {
  method: 'POST',
  body: {
    values: {
      title: 'Hello world',
      body: 'My first post',
      author: session.userId,
      published: true,
    },
    returning: '*',
  },
})

console.log(created[0].id)

Update records

js
import { request, session } from './lib/api.js'

await request('/table/posts/update', {
  method: 'POST',
  body: {
    where: `author == '${session.userId}' & published == false`,
    setValues: {
      published: true,
    },
    returning: '*',
  },
})

Edit one record by ID

js
import { request } from './lib/api.js'

await request('/table/posts/edit/POST_ID_HERE', {
  method: 'POST',
  body: {
    title: 'Updated title',
  },
})

Delete records

js
import { request, session } from './lib/api.js'

await request('/table/posts/delete', {
  method: 'POST',
  body: {
    where: `author == '${session.userId}' & published == false`,
    returning: '*',
  },
})