> ## Documentation Index
> Fetch the complete documentation index at: https://docs.markpdf.tech/llms.txt
> Use this file to discover all available pages before exploring further.

# Guía del marco: enrutador de aplicaciones

> Controladores de ruta, acciones del servidor y cómo mantener la clave API fuera del cliente.

# Guía del marco: enrutador de aplicaciones

`@markpdf/nextjs` cubre los dos patrones comunes de App Router para exponer la conversión de documentos a su interfaz de usuario: **Controladores de ruta** (cuando desea su propio punto final HTTP, por ejemplo, para llamarlo desde `fetch` en el cliente o desde otro servicio) y **Acciones del servidor** (cuando el formulario y la lógica del servidor se encuentran en el mismo archivo, sin definir una ruta).

## Regla general: la clave API nunca sale del servidor

El paquete completo supone que se importa únicamente desde:

* Controladores de ruta (`app/**/route.ts`)
* Acciones del servidor (`"use server"`)
* Componentes del servidor

<Warning>
  Si importa `@markpdf/nextjs` desde un componente de cliente (`"use client"`), el paquete fallará o, peor aún, el paquete final terminará necesitando la clave en el navegador. El paquete está diseñado para no funcionar fuera del entorno del servidor Next.js.
</Warning>

## Controlador de ruta: `createConvertRouteHandler`

```ts app/api/convert/route.ts theme={null}
import { createConvertRouteHandler } from "@markpdf/nextjs";

export const { POST } = createConvertRouteHandler({
  apiKey: process.env.MARKPDF_API_KEY!,
  defaultOptions: { mode: "fast", clean: true },
  maxUploadBytes: 25 * 1024 * 1024, // optional, rejects with your own 413 before calling the API
});
```

<ParamField body="apiKey" type="string" required>
  Su clave API. Léelo siempre desde `process.env`, nunca lo codifiques.
</ParamField>

<ParamField body="defaultOptions" type="ConvertOptions" />

<ParamField body="maxUploadBytes" type="number">
  Límite propio antes de reenviar a API: útil para reducir cargas enormes en el borde de tu aplicación sin gastar API cuota.
</ParamField>

El controlador generado:

1. Analice `multipart/form-data` de `Request`.
2. Reenvíe el archivo a `POST /convert/raw` con `@markpdf/sdk`.
3. Devuelve la respuesta para API tal cual (Markdown o JSON), incluido el `content-type` correcto.
4. Traduzca los errores de SDK (`MarkpdfAuthError`, `MarkpdfPayloadTooLargeError`, etc.) a HTTP respuestas con el mismo código de estado.

### Personaliza el controlador

Si necesita lógica adicional (autenticación de su propia aplicación, registro, su propia limitación de velocidad), utilice el cliente directamente en lugar del asistente todo en uno:

```ts app/api/convert/route.ts theme={null}
import { MarkpdfClient } from "@markpdf/sdk";
import { NextRequest, NextResponse } from "next/server";

const client = new MarkpdfClient({ apiKey: process.env.MARKPDF_API_KEY! });

export async function POST(req: NextRequest) {
  const session = await getSession(req);
  if (!session) return NextResponse.json({ error: "no autorizado" }, { status: 401 });

  const form = await req.formData();
  const file = form.get("file") as File;

  try {
    const markdown = await client.convertFile(file, { filename: file.name, mode: "fast" });
    return new NextResponse(markdown, { headers: { "content-type": "text/markdown" } });
  } catch (err) {
    return NextResponse.json({ error: String(err) }, { status: 502 });
  }
}
```

## Acción del servidor: `convertFormData` y `convertUrlAction`

```ts app/actions.ts theme={null}
"use server";

import { convertFormData, convertUrlAction } from "@markpdf/nextjs";

export async function convertUpload(formData: FormData) {
  return convertFormData(formData, {
    apiKey: process.env.MARKPDF_API_KEY!,
    fileField: "file",
    mode: "fast",
  });
}

export async function convertFromSignedUrl(url: string) {
  return convertUrlAction(url, {
    apiKey: process.env.MARKPDF_API_KEY!,
    mode: "fast",
  });
}
```

Las acciones del servidor se comportan como funciones normales de Node desde el punto de vista del cliente: Next.js serializa la llamada por usted. No es necesario exponer ninguna ruta.

<Tip>
  Utilice Acciones del servidor cuando el formulario de carga se encuentre en el mismo componente que desencadena la conversión (menos el texto estándar). Utilice un controlador de ruta cuando otro servicio, un webhook o un cliente que no sea su aplicación Next.js necesite llamar al punto final directamente.
</Tip>

## Transmisión en un controlador de ruta

```ts app/api/convert/stream/route.ts theme={null}
import { MarkpdfClient } from "@markpdf/sdk";

const client = new MarkpdfClient({ apiKey: process.env.MARKPDF_API_KEY! });

export async function POST(req: Request) {
  const { url } = await req.json();

  const encoder = new TextEncoder();
  const stream = new ReadableStream({
    async start(controller) {
      for await (const chunk of client.convertStream({ url })) {
        controller.enqueue(encoder.encode(chunk));
      }
      controller.close();
    },
  });

  return new Response(stream, { headers: { "content-type": "text/markdown; charset=utf-8" } });
}
```

Next.js reenvía `ReadableStream` al cliente sin almacenamiento en búfer, por lo que el cliente comienza a recibir Markdown antes de que finalice la conversión. Consulte [Transmisión y asíncrono](/docs/public/es/sdks/nextjs/streaming-and-async).

## Tiempo de ejecución: nodo frente a borde

`@markpdf/nextjs` funciona en ambos tiempos de ejecución de Next.js:

```ts app/api/convert/route.ts theme={null}
export const runtime = "nodejs"; // default; soporta uploads grandes sin lílimits de memoria del edge
// o
export const runtime = "edge"; // colder, but starts faster; stricter payload size limits
```

<Note>
  Para cargas grandes (PDF de decenas de MB), utilice `runtime = "nodejs"`. El tiempo de ejecución perimetral de Next.js tiene límites de tamaño de solicitud más bajos que dependen de su proveedor de alojamiento.
</Note>
