統合ガイド · FRONTEND & NEXT.JS
Next.js フォーム バックエンド統合 (アプリルーターとサーバーアクション)
Lugatu エンドポイントとサーバー アクションを使用して、資格情報の漏洩をゼロにして Next.js 14/15 でコンタクト フォームを処理するための完全な TypeScript および React 実装ガイド。
1. サーバーアクションを備えた Next.js アプリルーターアーキテクチャ
Next.js サーバー アクションはサーバー上で排他的に実行されるため、クライアント バンドルのシークレットを公開せずにプライベート Lugatu API キーを使用して問い合わせを送信するのに最適です。
app/actions/contact.ts
typescript
'use server';
export async function submitContact(prevState: any, formData: FormData) {
// Silent rejection of automated bot submissions via honeypot trap
const honeypot = (formData.get('_gotcha') as string) || '';
if (honeypot) {
return { success: true, error: null };
}
const name = formData.get('name') as string;
const email = formData.get('email') as string;
const message = formData.get('message') as string;
if (!name || !email || !message) {
return { success: false, error: 'All fields are required.' };
}
const payload = {
fields: { name, email, message },
};
try {
const res = await fetch(`https://www.lugatu.com/api/v1/forms/${process.env.LUGATU_FORM_ID}/submissions`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.LUGATU_API_KEY}`,
'Content-Type': 'application/json',
'Idempotency-Key': crypto.randomUUID(),
},
body: JSON.stringify(payload),
});
if (!res.ok) {
return { success: false, error: 'Failed to submit form.' };
}
return { success: true, error: null };
} catch (err) {
return { success: false, error: 'Network error occurred.' };
}
}
2. ロード状態のクライアント側フォームコンポーネント
アクセス可能な読み込みインジケーターを使用して、サーバー アクションを React 19 / Next.js クライアント コンポーネントに接続します。
components/ContactForm.tsx
tsx
'use client';
import { useActionState } from 'react';
import { submitContact } from '@/app/actions/contact';
export function ContactForm() {
const [state, formAction, isPending] = useActionState(submitContact, { success: false, error: null });
return (
<form action={formAction} className="space-y-4 max-w-md">
<div>
<label className="block text-sm font-semibold mb-1">Name</label>
<input name="name" required className="w-full border rounded-xl p-2.5" />
</div>
<div>
<label className="block text-sm font-semibold mb-1">Email</label>
<input type="email" name="email" required className="w-full border rounded-xl p-2.5" />
</div>
<div>
<label className="block text-sm font-semibold mb-1">Message</label>
<textarea name="message" rows={4} required className="w-full border rounded-xl p-2.5" />
</div>
<input type="text" name="_gotcha" style={{ display: 'none' }} tabIndex={-1} autoComplete="off" />
<button type="submit" disabled={isPending} className="btn-primary-editorial w-full py-2.5">
{isPending ? 'Sending...' : 'Send Message'}
</button>
{state.success && <p className="text-emerald-700 text-sm">Thank you! Your message was received.</p>}
{state.error && <p className="text-red-700 text-sm">{state.error}</p>}
</form>
);
}
セキュリティと認証の不変性
セキュリティに関する指示: LUGATU_API_KEY の前に NEXT_PUBLIC_ を決して付けないでください。 ライブ API キーを安全に保持できるのは、サーバー側のプライベート変数のみです。
トラブルシューティングと一般的な取り込みエラー
API キー要求が 403 FORBIDDEN_BROWSER_ORIGIN を返す
API キーを使用してクライアント側のブラウザ コードから fetch() 呼び出しを行っています。 Next.js サーバー アクションに切り替えるか、API キーなしでパブリック フォーム エンドポイントを使用します。
よくある質問
これを Vercel または Cloudflare Pages にデプロイできますか?
はい。 サーバー アクションは、Next.js でサポートされているサーバーレス プラットフォームとエッジ ランタイム間でシームレスに動作します。
フォームエンドポイントを作成する準備はできましたか?
数秒で無料で始められます。 クレジットカードは必要ありません。