API 라우트를 사용하여 양식 작성
HTML 양식을 사용하면 브라우저가 페이지를 새로 고치거나 새 페이지로 이동합니다. 대신 양식 데이터를 API 엔드포인트로 보내려면 JavaScript를 사용하여 양식 제출을 가로채야 합니다.
이 레시피는 양식 데이터를 API 엔드포인트로 보내고 해당 데이터를 처리하는 방법을 보여줍니다.
전제 조건
- 요청 시 렌더링을 위한 어댑터를 사용하는 프로젝트가 필요합니다.
- 설치된 UI 프레임워크 통합이 필요합니다.
레시피
양식 데이터를 수신할
/api/feedback에POSTAPI 엔드포인트를 생성합니다. 처리하려면request.formData()를 사용하세요. 사용하기 전에 양식 값의 유효성을 검사하세요.이 예시에서는 메시지와 함께 JSON 객체를 클라이언트에 다시 보냅니다.
export const prerender = false; // 'server' 모드에서는 필요하지 않습니다. import 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"); // 데이터 유효성을 검사합니다. 아마도 이보다 더 많은 작업을 수행하고 싶을 것입니다. if (!name || !email || !message) { return new Response( JSON.stringify({ message: "Missing required fields", }), { status: 400 } ); } // 데이터로 작업을 수행한 다음 성공 응답을 반환합니다. return new Response( JSON.stringify({ message: "Success!" }), { status: 200 } ); };UI 프레임워크를 사용하여 양식 컴포넌트를 만듭니다. 각 입력에는 해당 입력의 값을 설명하는
name속성이 있어야 합니다.양식을 제출하려면
<button>또는<input type="submit">요소를 포함해야 합니다.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> ); }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> ); }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> ); }<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> <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>제출 이벤트를 받아들이는 함수를 만든 다음 이를
submit핸들러로 양식에 전달합니다.함수에서는 다음을 수행합니다.
- 이벤트에서
preventDefault()를 호출하여 브라우저의 기본 제출 프로세스를 재정의합니다. FormData객체를 생성하고fetch()를 사용하여POST요청으로 엔드포인트에 보냅니다.
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> ); }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> ); }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> ); }<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><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>- 이벤트에서
<FeedbackForm />컴포넌트를 가져와 페이지에 포함합니다. 양식 로직이 원할 때 수화되도록 하려면client:*지시어를 사용하세요.--- import FeedbackForm from "../components/FeedbackForm" --- <FeedbackForm client:load />--- import FeedbackForm from "../components/FeedbackForm" --- <FeedbackForm client:load />--- import FeedbackForm from "../components/FeedbackForm" --- <FeedbackForm client:load />--- import FeedbackForm from "../components/FeedbackForm.svelte" --- <FeedbackForm client:load />--- import FeedbackForm from "../components/FeedbackForm.vue" --- <FeedbackForm client:load />