API Auto-generada de Supabase

Una de las características más poderosas de Supabase es que genera automáticamente una API REST completa basada en tu esquema de base de datos. Cada tabla, vista y función de PostgreSQL se convierte en un endpoint accesible via HTTP. No escribes código backend -- lo crea PostgREST por ti.

Qué es PostgREST

PostgREST es un servidor standalone que convierte tu base de datos PostgreSQL en una API REST. Supabase lo usa internamente como el motor de su API auto-generada.

Cuando creas una tabla productos en tu base de datos, PostgREST automáticamente expone:

  • GET /rest/v1/productos -- listar productos
  • POST /rest/v1/productos -- crear un producto
  • PATCH /rest/v1/productos?id=eq.123 -- actualizar un producto
  • DELETE /rest/v1/productos?id=eq.123 -- eliminar un producto

No necesitas definir rutas, controladores ni schemas. PostgREST lee la estructura de tu base de datos y genera todo.

Estructura de la URL

La URL base de tu API sigue este patrón:

plaintext
https://<tu-proyecto>.supabase.co/rest/v1/<tabla>

Ejemplos:

plaintext
https://abcdef.supabase.co/rest/v1/productos
https://abcdef.supabase.co/rest/v1/usuarios
https://abcdef.supabase.co/rest/v1/pedidos

Cuando usas el SDK, no necesitas construir estas URLs manualmente -- el SDK lo hace por ti. Pero es útil entender la estructura para debugging o para cuando necesites hacer requests directos.

Headers de autenticación

Toda request a la API de Supabase necesita al menos un header: apikey. Dependiendo de lo que necesites, puedes agregar Authorization también.

apikey (obligatorio)

plaintext
apikey: tu-anon-key-o-service-role-key

Este header identifica tu proyecto. Usas la anon key para requests desde el cliente y la service_role key para requests desde el servidor.

Authorization (para usuarios autenticados)

plaintext
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

Cuando un usuario se loguea, Supabase le da un JWT (JSON Web Token -- un token firmado que contiene la identidad del usuario). Ese token va en el header Authorization. Las políticas de RLS usan este token para determinar qué datos puede ver o modificar el usuario.

Ejemplo con ambos headers

typescript
const response = await fetch(
  `${process.env.NEXT_PUBLIC_SUPABASE_URL}/rest/v1/productos?select=*`,
  {
    headers: {
      'apikey': process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
      'Authorization': `Bearer ${session.access_token}`,
      'Content-Type': 'application/json',
    },
  }
)
 
const productos = await response.json()
El SDK hace esto por ti

Cuando usas supabase.from('productos').select('*'), el SDK agrega estos headers automáticamente. El ejemplo con fetch directo es para que entiendas qué pasa por debajo.

Requests con fetch vs SDK

Puedes interactuar con la API de dos formas: usando fetch directamente o usando el SDK. El SDK es más cómodo, pero hay situaciones donde fetch tiene sentido.

Con el SDK (recomendado)

typescript
import { supabase } from '@/lib/supabase'
 
// SELECT
const { data, error } = await supabase
  .from('productos')
  .select('id, nombre, precio')
  .eq('activo', true)
  .order('precio', { ascending: true })
 
// INSERT
const { data, error } = await supabase
  .from('productos')
  .insert({ nombre: 'Laptop', precio: 999.99 })
  .select()
 
// UPDATE
const { data, error } = await supabase
  .from('productos')
  .update({ precio: 899.99 })
  .eq('id', 123)
  .select()
 
// DELETE
const { error } = await supabase
  .from('productos')
  .delete()
  .eq('id', 123)

Con fetch directo

typescript
const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL!
const supabaseKey = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
 
// SELECT
const response = await fetch(
  `${supabaseUrl}/rest/v1/productos?select=id,nombre,precio&activo=eq.true&order=precio.asc`,
  {
    headers: {
      'apikey': supabaseKey,
      'Authorization': `Bearer ${supabaseKey}`,
    },
  }
)
 
// INSERT
const response = await fetch(
  `${supabaseUrl}/rest/v1/productos`,
  {
    method: 'POST',
    headers: {
      'apikey': supabaseKey,
      'Authorization': `Bearer ${supabaseKey}`,
      'Content-Type': 'application/json',
      'Prefer': 'return=representation',
    },
    body: JSON.stringify({ nombre: 'Laptop', precio: 999.99 }),
  }
)
Cuando usar fetch directo

Usa fetch cuando necesites control total sobre los headers (por ejemplo, para paginación con Range), cuando estés en un entorno donde no puedes instalar el SDK, o cuando necesites integrar con herramientas que trabajan con REST puro.

El header Prefer

PostgREST usa el header Prefer para configurar el comportamiento de la respuesta:

ValorEfecto
return=representationDevuelve los datos insertados/actualizados
return=minimalNo devuelve datos (solo status)
return=headers-onlyDevuelve solo headers
count=exactIncluye el conteo exacto de filas
count=plannedIncluye un conteo estimado (más rápido)

Cuando usas el SDK con .select() después de un .insert() o .update(), el SDK agrega Prefer: return=representation automáticamente.

OpenAPI spec

Supabase genera una especificación OpenAPI (antes conocida como Swagger -- un formato estándar que describe los endpoints de tu API) basada en tu esquema. Puedes acceder a ella en:

plaintext
https://<tu-proyecto>.supabase.co/rest/v1/?apikey=tu-anon-key

Esta spec es útil para:

  • Generar tipos de TypeScript (el CLI lo hace con supabase gen types)
  • Importar en Postman o Insomnia para probar endpoints
  • Documentar tu API automáticamente

API docs en el dashboard

En el dashboard de Supabase, ve a API Docs en el menú lateral. Ahí encuentras documentación auto-generada de toda tu API con:

  • Endpoints disponibles por tabla
  • Parámetros de query soportados
  • Ejemplos de código en JavaScript, cURL y otros lenguajes
  • Tipos de datos de cada columna

Cada vez que modificas tu esquema (agregas una tabla, una columna o una vista), la documentación se actualiza sola.

Generador de código

En la sección API Docs del dashboard, puedes seleccionar una tabla y Supabase te genera el código exacto para hacer queries. Es un buen punto de partida cuando no te acuerdas de la sintaxis de algún filtro.

Vistas como endpoints

Las vistas de PostgreSQL también se exponen como endpoints REST. Esto es útil para crear queries complejas que quieres reutilizar:

sql
-- Crear una vista en el SQL Editor del dashboard
CREATE VIEW productos_con_stock AS
SELECT p.id, p.nombre, p.precio, i.cantidad as stock
FROM productos p
JOIN inventario i ON p.id = i.producto_id
WHERE i.cantidad > 0;

Ahora puedes consultar esta vista como si fuera una tabla:

typescript
const { data } = await supabase
  .from('productos_con_stock')
  .select('*')
  .order('precio', { ascending: true })

Funciones RPC

Las funciones de PostgreSQL se exponen via RPC (Remote Procedure Call -- llamar una función remota). Si tienes una función SQL:

sql
CREATE FUNCTION buscar_productos(termino text)
RETURNS SETOF productos AS $$
  SELECT * FROM productos
  WHERE nombre ILIKE '%' || termino || '%'
$$ LANGUAGE sql;

La llamas desde el SDK:

typescript
const { data } = await supabase
  .rpc('buscar_productos', { termino: 'laptop' })

O con fetch:

plaintext
POST /rest/v1/rpc/buscar_productos
Body: { "termino": "laptop" }

Resumen

ConceptoDetalle
MotorPostgREST convierte PostgreSQL en REST API
URL basehttps://<proyecto>.supabase.co/rest/v1/<tabla>
Header obligatorioapikey con tu anon key o service_role key
Auth de usuarioAuthorization: Bearer <jwt>
SDK vs fetchSDK para el 90% de los casos, fetch para control fino
OpenAPISpec auto-generada para documentación y tooling
VistasSe exponen como endpoints igual que las tablas
FuncionesAccesibles via .rpc() o POST /rpc/nombre