Construir formularios con rutas de API
Un formulario HTML hace que el navegador refresque la página o navegue a una nueva. Para enviar datos del formulario a un endpoint de API en su lugar, debes interceptar el envío del formulario usando JavaScript.
Esta receta te muestra cómo enviar datos del formulario a un endpoint de API y manejar esos datos.
Requisitos previos
Sección titulada “Requisitos previos”- Un proyecto con un adapter para renderizado on-demand
- Una integración de UI Framework instalada
-
Crea un endpoint
POSTen/api/feedbackque recibirá los datos del formulario. Usarequest.formData()para procesarlo. Asegúrate de validar los valores del formulario antes de usarlos.Este ejemplo envía un objeto JSON con un mensaje de vuelta al cliente.
src/pages/api/feedback.ts export const prerender = false; // Not needed in 'server' modeimport type { APIRoute } from "astro";export const POST: APIRoute = async ({ request }) => {const data = await request.formData();const name = data.get("name");const email = data.get("email");const message = data.get("message");// Validate the data - you'll probably want to do more than thisif (!name || !email || !message) {return new Response(JSON.stringify({message: "Missing required fields",}),{ status: 400 });}// Do something with the data, then return a success responsereturn new Response(JSON.stringify({message: "Success!"}),{ status: 200 });}; -
Crea un componente de formulario usando tu framework de UI. Cada input debería tener un atributo
nameque describa el valor de ese input.Asegúrate de incluir un elemento
<button>o<input type="submit">para enviar el formulario.src/components/FeedbackForm.tsx export default function Form() {return (<form><label>Name<input type="text" id="name" name="name" required /></label><label>Email<input type="email" id="email" name="email" required /></label><label>Message<textarea id="message" name="message" required /></label><button>Send</button></form>);}src/components/FeedbackForm.tsx export default function Form() {return (<form><label>Name<input type="text" id="name" name="name" required /></label><label>Email<input type="email" id="email" name="email" required /></label><label>Message<textarea id="message" name="message" required /></label><button>Send</button></form>);}src/components/FeedbackForm.tsx export default function Form() {return (<form><label>Name<input type="text" id="name" name="name" required /></label><label>Email<input type="email" id="email" name="email" required /></label><label>Message<textarea id="message" name="message" required /></label><button>Send</button></form>);}src/components/FeedbackForm.svelte <form><label>Name<input type="text" id="name" name="name" required /></label><label>Email<input type="email" id="email" name="email" required /></label><label>Message<textarea id="message" name="message" required /></label><button>Send</button></form>src/components/FeedbackForm.vue <template><form><label>Name<input type="text" id="name" name="name" required /></label><label>Email<input type="email" id="email" name="email" required /></label><label>Message<textarea id="message" name="message" required /></label><button>Send</button></form></template> -
Crea una función que acepte un evento de submit, luego pásala como handler de
submita tu formulario.En la función:
- Llama a
preventDefault()en el evento para sobrescribir el proceso de envío por defecto del navegador. - Crea un objeto
FormDatay envíalo en una peticiónPOSTa tu endpoint usandofetch().
src/components/FeedbackForm.tsx import { useState } from "preact/hooks";export default function Form() {const [responseMessage, setResponseMessage] = useState("");async function submit(e: SubmitEvent) {e.preventDefault();const formData = new FormData(e.target as HTMLFormElement);const response = await fetch("/api/feedback", {method: "POST",body: formData,});const data = await response.json();if (data.message) {setResponseMessage(data.message);}}return (<form onSubmit={submit}><label>Name<input type="text" id="name" name="name" required /></label><label>Email<input type="email" id="email" name="email" required /></label><label>Message<textarea id="message" name="message" required /></label><button>Send</button>{responseMessage && <p>{responseMessage}</p>}</form>);}src/components/FeedbackForm.tsx import { useState } from "react";import type { FormEvent } from "react";export default function Form() {const [responseMessage, setResponseMessage] = useState("");async function submit(e: FormEvent<HTMLFormElement>) {e.preventDefault();const formData = new FormData(e.target as HTMLFormElement);const response = await fetch("/api/feedback", {method: "POST",body: formData,});const data = await response.json();if (data.message) {setResponseMessage(data.message);}}return (<form onSubmit={submit}><label htmlFor="name">Name<input type="text" id="name" name="name" autoComplete="name" required /></label><label htmlFor="email">Email<input type="email" id="email" name="email" autoComplete="email" required /></label><label htmlFor="message">Message<textarea id="message" name="message" autoComplete="off" required /></label><button>Send</button>{responseMessage && <p>{responseMessage}</p>}</form>);}src/components/FeedbackForm.tsx import { createSignal, createResource, Suspense } from "solid-js";async function postFormData(formData: FormData) {const response = await fetch("/api/feedback", {method: "POST",body: formData,});const data = await response.json();return data;}export default function Form() {const [formData, setFormData] = createSignal<FormData>();const [response] = createResource(formData, postFormData);function submit(e: SubmitEvent) {e.preventDefault();setFormData(new FormData(e.target as HTMLFormElement));}return (<form onSubmit={submit}><label>Name<input type="text" id="name" name="name" required /></label><label>Email<input type="email" id="email" name="email" required /></label><label>Message<textarea id="message" name="message" required /></label><button>Send</button><Suspense>{response() && <p>{response().message}</p>}</Suspense></form>);}src/components/FeedbackForm.svelte <script lang="ts">let responseMessage: string;async function submit(e: SubmitEvent) {e.preventDefault();const formData = new FormData(e.currentTarget as HTMLFormElement);const response = await fetch("/api/feedback", {method: "POST",body: formData,});const data = await response.json();responseMessage = data.message;}</script><form on:submit={submit}><label>Name<input type="text" id="name" name="name" required /></label><label>Email<input type="email" id="email" name="email" required /></label><label>Message<textarea id="message" name="message" required /></label><button>Send</button>{#if responseMessage}<p>{responseMessage}</p>{/if}</form>src/components/FeedbackForm.vue <script setup lang="ts">import { ref } from "vue";const responseMessage = ref<string>();async function submit(e: Event) {e.preventDefault();const formData = new FormData(e.currentTarget as HTMLFormElement);const response = await fetch("/api/feedback", {method: "POST",body: formData,});const data = await response.json();responseMessage.value = data.message;}</script><template><form @submit="submit"><label>Name<input type="text" id="name" name="name" required /></label><label>Email<input type="email" id="email" name="email" required /></label><label>Message<textarea id="message" name="message" required /></label><button>Send</button><p v-if="responseMessage">{{ responseMessage }}</p></form></template> - Llama a
-
Importa e incluye tu componente
<FeedbackForm />en una página. Asegúrate de usar una directivaclient:*para asegurar que la lógica del formulario se hidrate cuando quieras que lo haga.src/pages/index.astro ---import FeedbackForm from "../components/FeedbackForm"---<FeedbackForm client:load />src/pages/index.astro ---import FeedbackForm from "../components/FeedbackForm"---<FeedbackForm client:load />src/pages/index.astro ---import FeedbackForm from "../components/FeedbackForm"---<FeedbackForm client:load />src/pages/index.astro ---import FeedbackForm from "../components/FeedbackForm.svelte"---<FeedbackForm client:load />src/pages/index.astro ---import FeedbackForm from "../components/FeedbackForm.vue"---<FeedbackForm client:load />