Supabase
Instalaciones
npm i @supabase/supabase-js
bun add @supabase/supabase-js
Variables de entorno
name = ""
compatibility_date = "2023-12-01"
[vars]
SUPABASE_URL=""
SUPABASE_KEY=""
Middleware
- Agregar el cliente de Supabase al contexto para extraerlo fácilmente en cualquier ruta
src\middleware\supabase.ts
import { createClient, SupabaseClient } from "@supabase/supabase-js";
import { Context, MiddlewareHandler } from "hono";
export const idCtxSupabase = "supabase-ctx";
/** Supabase Middleware
* Crea el cliente de Supabase y lo agrega al contexto
* Para usarlo en las rutas
*/
export const supabaseMiddleware: MiddlewareHandler = async (c, next) => {
try {
if (getSupabase(c)) return await next();
// Validar variables de entorno
if (!c.env.SUPABASE_URL || !c.env.SUPABASE_KEY) {
throw new Error("Variables de entorno de Supabase no definidas");
}
// Crear cliente de Supabase y agregarlo al contexto
const supabase = createClient(c.env.SUPABASE_URL, c.env.SUPABASE_KEY);
c.set(idCtxSupabase, supabase);
await next();
} catch (error: any) {
return c.json({ error: error.message }, 500);
}
};
/**
* Obtiene el cliente de Supabase del contexto listo para usar
* @param c Contexto
*/
export const getSupabase = (c: Context): SupabaseClient => c.get(idCtxSupabase);
- Agregar al
app.use()
src\users\index.ts
const userApp = new Hono();
// Agregar middleware al módulo de usuarios
userApp.use("*", supabaseMiddleware);
userApp.get("/", async (c) => {}
Uso
import { Hono } from "hono";
import { getSupabase, supabaseMiddleware } from "../middleware/supabase";
import { zUserValidator } from "./validator";
const userApp = new Hono();
// Agregar middleware al módulo de usuarios
userApp.use("*", supabaseMiddleware);
userApp.get("/", async (c) => {
const supabase = getSupabase(c); // Extraer el cliente del Ctx
const { data, error } = await supabase.from("users").select("*");
return c.json({ data, error });
});
//userApp.post("/", zValidator("form", userSchema), async (c) => { });
userApp.post("/", zUserValidator, async (c) => {
// Extraer el cuerpo de la petición (ya validado)
// form-data, x-www-form-urlencoded
const body = await c.req.parseBody();
const supabase = getSupabase(c);
const { data, error } = await supabase.from("users").insert(body).select();
return c.json({ data, error });
});
export default userApp; // import userApp from "./users";
// export { userApp }; // import { userApp } from "./users";
Archivos
src\storage\index.ts
import { Hono } from "hono";
import { getMimeType } from "hono/utils/mime";
import { getSupabase, supabaseMiddleware } from "../middleware/supabase";
export type Env = {
SUPABASE_URL: string;
SUPABASE_KEY: string;
};
const storage = new Hono<{ Bindings: Env }>();
storage.post("/upload", supabaseMiddleware, async (c) => {
const supabase = getSupabase(c);
const body = await c.req.parseBody();
const file = body["file"] as File;
const { data, error } = await supabase.storage
.from("FirstBucket")
.upload(`public/users/${file.name}`, file);
return c.json({ data, error });
});
storage.get("/download/:filename", supabaseMiddleware, async (c) => {
const supabase = getSupabase(c);
const { filename } = c.req.param();
const { data, error } = await supabase.storage
.from("FirstBucket")
.download(`public/users/${filename}`);
if (error) return c.json({ error: error.message }, 500);
if (!data) return c.json({ error: "File not found" }, 404);
// Convertir el archivo a un Uint8Array
const uint8Array = new Uint8Array(await data!.arrayBuffer());
// Determinar el tipo MIME basado en la extensión del archivo
const mimeType = getMimeType(filename) || "";
// Devolver la imagen con el tipo MIME correcto
return c.body(uint8Array, 200, {
"Content-Type": mimeType,
"Content-Disposition": `inline; filename="${filename}"`,
});
});
export default storage;