Next.js + Transloadit
Usa Uppy en un Client Component y un pequeño endpoint del App Router que firma un Template fijo de Transloadit sin exponer el Auth Secret.
Receta ejecutable
Crea la integración
La ruta del servidor firma un Template fijo y el Client Component le entrega a Uppy los parámetros firmados antes de cada subida.
- Crea un Template de Transloadit y guarda su ID, su Auth Key y su Auth Secret en variables de entorno del servidor.
- Añade el Route Handler y protégelo con las mismas comprobaciones de autorización que el resto de tu aplicación.
- Renderiza el Client Component UploadForm en una página y selecciona un archivo para ejecutar el Template.
Instalar
yarn add @uppy/core @uppy/dashboard @uppy/react @uppy/transloadit transloaditapp/api/transloadit/route.ts
import { NextResponse } from 'next/server'
import { Transloadit } from 'transloadit'
export async function POST() {
const authKey = process.env.TRANSLOADIT_KEY
const authSecret = process.env.TRANSLOADIT_SECRET
const templateId = process.env.TRANSLOADIT_TEMPLATE_ID
if (!authKey || !authSecret || !templateId) {
return NextResponse.json({ error: 'Server configuration is incomplete' }, { status: 500 })
}
const transloadit = new Transloadit({ authKey, authSecret })
const requestParams = {
auth: { expires: new Date(Date.now() + 5 * 60 * 1000).toISOString() },
template_id: templateId,
}
const { params, signature } = transloadit.calcSignature(requestParams)
return NextResponse.json(
{ params, signature },
{ headers: { 'Cache-Control': 'private, no-store' } },
)
}app/UploadForm.tsx
'use client'
import Uppy from '@uppy/core'
import TransloaditPlugin from '@uppy/transloadit'
import Dashboard from '@uppy/react/dashboard'
import { useEffect, useState } from 'react'
import '@uppy/core/css/style.min.css'
import '@uppy/dashboard/css/style.min.css'
export function UploadForm() {
const [uppy, setUppy] = useState<Uppy | null>(null)
useEffect(() => {
const instance = new Uppy().use(TransloaditPlugin, {
waitForEncoding: true,
async assemblyOptions() {
const response = await fetch('/api/transloadit', { method: 'POST' })
if (!response.ok) throw new Error('Could not authorize upload')
return response.json()
},
})
setUppy(instance)
return () => instance.destroy()
}, [])
return uppy == null ? null : <Dashboard uppy={uppy} />
}Autenticación
- Guarda TRANSLOADIT_SECRET en una variable de entorno del servidor sin prefijo. Next.js expone a los bundles del navegador las variables con el prefijo NEXT_PUBLIC_.
- El Route Handler usa el SDK oficial de Node para firmar el ID del Template fijo con una caducidad de cinco minutos y devuelve al navegador solo params y una firma.
- Exige la autorización de usuario que necesite tu producto antes de devolver una firma, y no aceptes IDs de Template ni Steps arbitrarios desde el navegador.
Limitaciones y notas operativas
- El navegador no puede proteger un Auth Secret. La generación de firmas y las comprobaciones de autorización deben permanecer en código exclusivo del servidor.
- waitForEncoding mantiene la interfaz de subida en espera del procesamiento. Para trabajos largos, usa Assembly Notifications o recupera la Assembly más tarde.
- El ejemplo autoriza un Template fijo. Los campos dinámicos siguen necesitando validación del lado del servidor antes de incluirse en los parámetros firmados.
Más integraciones