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 productosPOST /rest/v1/productos-- crear un productoPATCH /rest/v1/productos?id=eq.123-- actualizar un productoDELETE /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:
https://<tu-proyecto>.supabase.co/rest/v1/<tabla>Ejemplos:
https://abcdef.supabase.co/rest/v1/productos
https://abcdef.supabase.co/rest/v1/usuarios
https://abcdef.supabase.co/rest/v1/pedidosCuando 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)
apikey: tu-anon-key-o-service-role-keyEste 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)
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
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)
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
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:
| Valor | Efecto |
|---|---|
return=representation | Devuelve los datos insertados/actualizados |
return=minimal | No devuelve datos (solo status) |
return=headers-only | Devuelve solo headers |
count=exact | Incluye el conteo exacto de filas |
count=planned | Incluye 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:
https://<tu-proyecto>.supabase.co/rest/v1/?apikey=tu-anon-keyEsta 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:
-- 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:
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:
CREATE FUNCTION buscar_productos(termino text)
RETURNS SETOF productos AS $$
SELECT * FROM productos
WHERE nombre ILIKE '%' || termino || '%'
$$ LANGUAGE sql;La llamas desde el SDK:
const { data } = await supabase
.rpc('buscar_productos', { termino: 'laptop' })O con fetch:
POST /rest/v1/rpc/buscar_productos
Body: { "termino": "laptop" }Resumen
| Concepto | Detalle |
|---|---|
| Motor | PostgREST convierte PostgreSQL en REST API |
| URL base | https://<proyecto>.supabase.co/rest/v1/<tabla> |
| Header obligatorio | apikey con tu anon key o service_role key |
| Auth de usuario | Authorization: Bearer <jwt> |
| SDK vs fetch | SDK para el 90% de los casos, fetch para control fino |
| OpenAPI | Spec auto-generada para documentación y tooling |
| Vistas | Se exponen como endpoints igual que las tablas |
| Funciones | Accesibles via .rpc() o POST /rpc/nombre |