Skip to main content
Envuelve una API externa inyectando credenciales desde secrets. El cliente llama a tu función, y tu función llama a la API real con las claves correctas. Patrón: ruta con parámetros + inyección de autenticación + transformación de respuesta.
index.ts
import { define, z } from "@jelou/functions";

export default define({
  name: "api-proxy",
  description: "Proxy a una API externa con autenticación inyectada",
  input: z.object({
    fields: z.array(z.string()).optional().describe("Campos a incluir en la respuesta"),
  }),
  config: {
    path: "/users/:id",
    methods: ["GET"],
    cors: {
      origin: "https://app.example.com",
      credentials: true,
    },
  },
  handler: async (input, ctx) => {
    const apiKey = ctx.env.get("INTERNAL_API_KEY");
    const baseUrl = ctx.env.get("API_BASE_URL");

    ctx.log("Proxy request", {
      userId: ctx.params.id,
      fields: input.fields,
    });

    const res = await fetch(
      `${baseUrl}/api/users/${ctx.params.id}`,
      { headers: { Authorization: `Bearer ${apiKey}` } },
    );

    if (!res.ok) {
      ctx.log("Upstream error", { status: res.status, userId: ctx.params.id });
      return { error: "not_found", status: res.status };
    }

    const user = await res.json();
    const result: Record<string, unknown> = {
      id: user.id,
      name: user.name,
      email: user.email,
    };

    if (input.fields?.includes("address")) {
      result.address = user.address;
    }
    if (input.fields?.includes("orders")) {
      result.recentOrders = user.orders?.slice(0, 5);
    }

    return result;
  },
});

Prueba local

curl "http://localhost:3000/users/42?fields=address,orders"

Por qué funciona así

  • config.path: "/users/:id" — el :id se captura en ctx.params.id.
  • Las credenciales nunca se exponen al cliente; viven en secrets.
  • cors.origin restringe qué dominios pueden llamar al proxy desde el navegador.
  • Puedes transformar o filtrar la respuesta antes de devolverla.