Introducción/Guías/Formularios

Cómo crear formularios con API Routes

Los formularios permiten crear y actualizar datos en aplicaciones web. Next.js ofrece una forma poderosa de manejar mutaciones de datos usando API Routes (Rutas de API). Esta guía le mostrará cómo procesar el envío de formularios en el servidor.

Formularios en el servidor

Para manejar envíos de formularios en el servidor, cree un endpoint de API para mutar datos de forma segura.

import type { NextApiRequest, NextApiResponse } from 'next'

export default async function handler(
  req: NextApiRequest,
  res: NextApiResponse
) {
  const data = req.body
  const id = await createItem(data)
  res.status(200).json({ id })
}

Luego, llame a la API Route desde el cliente con un manejador de eventos:

import { FormEvent } from 'react'

export default function Page() {
  async function onSubmit(event: FormEvent<HTMLFormElement>) {
    event.preventDefault()

    const formData = new FormData(event.currentTarget)
    const response = await fetch('/api/submit', {
      method: 'POST',
      body: formData,
    })

    // Maneje la respuesta si es necesario
    const data = await response.json()
    // ...
  }

  return (
    <form onSubmit={onSubmit}>
      <input type="text" name="name" />
      <button type="submit">Submit</button>
    </form>
  )
}

Nota importante:

  • Las API Routes no especifican cabeceras CORS, lo que significa que son solo del mismo origen por defecto.
  • Dado que las API Routes se ejecutan en el servidor, podemos usar valores sensibles (como claves de API) a través de Variables de Entorno sin exponerlos al cliente. Esto es crítico para la seguridad de su aplicación.

Validación de formularios

Recomendamos usar validación HTML como required y type="email" para validación básica en el cliente.

Para validación más avanzada en el servidor, puede usar una biblioteca de validación de esquemas como zod para validar los campos del formulario antes de mutar los datos:

import type { NextApiRequest, NextApiResponse } from 'next'
import { z } from 'zod'

const schema = z.object({
  // ...
})

export default async function handler(
  req: NextApiRequest,
  res: NextApiResponse
) {
  const parsed = schema.parse(req.body)
  // ...
}

Manejo de errores

Puede usar el estado de React para mostrar un mensaje de error cuando falla el envío de un formulario:

import React, { useState, FormEvent } from 'react'

export default function Page() {
  const [isLoading, setIsLoading] = useState<boolean>(false)
  const [error, setError] = useState<string | null>(null)

  async function onSubmit(event: FormEvent<HTMLFormElement>) {
    event.preventDefault()
    setIsLoading(true)
    setError(null) // Limpiar errores previos cuando comienza una nueva solicitud

    try {
      const formData = new FormData(event.currentTarget)
      const response = await fetch('/api/submit', {
        method: 'POST',
        body: formData,
      })

      if (!response.ok) {
        throw new Error('Error al enviar los datos. Por favor intente nuevamente.')
      }

      // Maneje la respuesta si es necesario
      const data = await response.json()
      // ...
    } catch (error) {
      // Capturar el mensaje de error para mostrar al usuario
      setError(error.message)
      console.error(error)
    } finally {
      setIsLoading(false)
    }
  }

  return (
    <div>
      {error && <div style={{ color: 'red' }}>{error}</div>}
      <form onSubmit={onSubmit}>
        <input type="text" name="name" />
        <button type="submit" disabled={isLoading}>
          {isLoading ? 'Cargando...' : 'Enviar'}
        </button>
      </form>
    </div>
  )
}

Mostrando estado de carga

Puede usar el estado de React para mostrar un estado de carga cuando un formulario se está enviando al servidor:

import React, { useState, FormEvent } from 'react'

export default function Page() {
  const [isLoading, setIsLoading] = useState<boolean>(false)

  async function onSubmit(event: FormEvent<HTMLFormElement>) {
    event.preventDefault()
    setIsLoading(true) // Establecer carga en true cuando comienza la solicitud

    try {
      const formData = new FormData(event.currentTarget)
      const response = await fetch('/api/submit', {
        method: 'POST',
        body: formData,
      })

      // Maneje la respuesta si es necesario
      const data = await response.json()
      // ...
    } catch (error) {
      // Maneje el error si es necesario
      console.error(error)
    } finally {
      setIsLoading(false) // Establecer carga en false cuando la solicitud se completa
    }
  }

  return (
    <form onSubmit={onSubmit}>
      <input type="text" name="name" />
      <button type="submit" disabled={isLoading}>
        {isLoading ? 'Cargando...' : 'Enviar'}
      </button>
    </form>
  )
}

Redireccionamiento

Si desea redirigir al usuario a una ruta diferente después de una mutación, puede usar redirect a cualquier URL absoluta o relativa:

import type { NextApiRequest, NextApiResponse } from 'next'

export default async function handler(
  req: NextApiRequest,
  res: NextApiResponse
) {
  const id = await addPost()
  res.redirect(307, `/post/${id}`)
}

On this page