Next.jsはReactをフロントエンドに利用したアプリケーションフレームワークです。Vercel向けにアプリケーションを開発する際によく使われています。
今回はそんなNext.jsとServerless Functions、blastengineを使ってお問い合わせフォームを実装します。
コード
今回のコードは https://github.com/blastengineMania/nextjs-contact にアップしてあります。実装時の参考にしてください。
実装について
フロントエンド
フロントエンドはNext.jsで実装します。入力項目は以下の通りです。
項目 | 型 | 変数名 |
---|---|---|
会社名 | テキスト | company |
名前 | テキスト | name |
メールアドレス | テキスト | mailaddress |
問い合わせ種別 | 選択 | type |
問い合わせ内容 | テキスト | body |
コードは以下のようになります。
ステートの準備
今回は以下のステートを用意しています。
// フォーム入力データの型
type formData = {
company: string;
name: string;
email: string;
type: string;
message: string;
};
// フォームの選択肢の型
type SelectOption = {
label: string;
value: string;
};
// フォームの初期値
const defaultValue: formData = {
company: '',
name: '',
email: '',
type: '',
message: '',
};
const options: SelectOption[] = [
{ label: 'お問い合わせ', value: 'お問い合わせ' },
{ label: 'ご意見', value: 'ご意見' },
{ label: 'その他', value: 'その他' },
];
const [form, setForm] = useState(defaultValue);
選択項目の表示
選択項目は options
で、動的に生成しています。
<div className="block type">
<label htmlFor="frm-type">お問い合わせ種別</label>
<select
onChange={(e) =>
setForm({ ...form, ...{ type: e.target.value } })
}
>
{options.map((option) => (
<option value={option.value}>{option.label}</option>
))}
</select>
</div>
フォームについて
フォームは以下のようになります。入力されたら、その値をフォームに反映しています。ボタンやフォームの送信時には send
関数を呼んでいます。
<>
<div className={styles.container}>
<Head>
<title>お問い合わせ</title>
</Head>
<main className={styles.main}>
<h3 className={styles.title}>お問い合わせ</h3>
<form className="container" onSubmit={send}>
<div className="company block">
<label htmlFor="frm-company">会社名</label>
<input
id="frm-company"
type="text"
value={form.company}
autoComplete="company"
onChange={(e) =>
setForm({ ...form, ...{ company: e.target.value } })
}
required
/>
</div>
<div className="account block">
<label htmlFor="frm-name">名前</label>
<input
id="frm-name"
type="text"
value={form.name}
autoComplete="name"
onChange={(e) =>
setForm({ ...form, ...{ name: e.target.value } })
}
required
/>
</div>
<div className="email block">
<label htmlFor="frm-email">メールアドレス</label>
<input
id="frm-email"
type="email"
value={form.email}
autoComplete="email"
onChange={(e) =>
setForm({ ...form, ...{ email: e.target.value } })
}
required
/>
</div>
<div className="block type">
<label htmlFor="frm-type">お問い合わせ種別</label>
<select
onChange={(e) =>
setForm({ ...form, ...{ type: e.target.value } })
}
>
{options.map((option) => (
<option value={option.value}>{option.label}</option>
))}
</select>
</div>
<div className="message block">
<label htmlFor="frm-message">Message</label>
<textarea
id="frm-message"
rows={6}
value={form.message}
onChange={(e) =>
setForm({ ...form, ...{ message: e.target.value } })
}
>
</textarea>
</div>
<button onClick={send}>送信</button>
</form>
</main>
</div>
</>
また、CSS(global.css)は以下のようになります。
html,
body {
padding: 0;
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen,
Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif;
background: #1e1e1e;
min-height: 100vh;
display: flex;
color: rgb(243, 241, 239);
justify-content: center;
align-items: center;
}
.block {
display: flex;
flex-direction: column;
}
.name {
display: flex;
flex-direction: row;
justify-content: space-between;
}
.container {
font-size: 1.3rem;
border-radius: 10px;
width: 85%;
padding: 50px;
box-shadow: 0 54px 55px rgb(78 78 78 / 25%), 0 -12px 30px rgb(78 78 78 / 25%),
0 4px 6px rgb(78 78 78 / 25%), 0 12px 13px rgb(78 78 78 / 25%),
0 -3px 5px rgb(78 78 78 / 25%);
}
.container input {
font-size: 1.2rem;
margin: 10px 0 10px 0px;
border-color: rgb(31, 28, 28);
padding: 10px;
border-radius: 5px;
background-color: #e8f0fe;
}
.container select {
font-size: 1.2rem;
margin: 10px 0 10px 0px;
border-color: rgb(31, 28, 28);
padding: 10px;
border-radius: 5px;
background-color: #e8f0fe;
}
.container textarea {
margin: 10px 0 10px 0px;
padding: 5px;
border-color: rgb(31, 28, 28);
border-radius: 5px;
background-color: #e8f0fe;
font-size: 20px;
}
.container h1 {
text-align: center;
font-weight: 600;
}
.name div {
display: flex;
flex-direction: column;
}
.block button {
padding: 10px;
font-size: 20px;
width: 30%;
border: 3px solid black;
border-radius: 5px;
}
.button {
display: flex;
align-items: center;
}
textarea {
resize: none;
}
送信した際の処理
送信ボタンを押した際の処理として、入力情報を POST /api/blastengine
に送信します。
// フォームの送信処理
const send = async (e: any) => {
e.preventDefault();
fetch('/api/blastengine', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(form),
});
};
Serverless Functions
まず .env
ファイルを作成して、以下の2つの環境変数を定義します。
環境設定名 | 値 |
---|---|
BLASTENGINE_USER_ID | 先ほど作成したAPIユーザー名 |
BLASTENGINE_API_KEY | 先ほど作成したAPIキー |
コードの作成
ライブラリの追加
プロジェクトへ、blastengine SDKを追加します。
npm i blastengine
基本形
コードは /pages/api/blastengine.ts
として作成します。基本形は以下の通りです。
import type { NextApiRequest, NextApiResponse } from 'next'
import { BlastEngine, Mail } from 'blastengine';
type Data = {
delivery_id: number
}
export default async function handler(
req: NextApiRequest,
res: NextApiResponse<Data>
) {
// この中に処理を書く
}
SDKの初期化
読み込んだblastengineのSDKを初期化します。
new BlastEngine(process.env.BLASTENGINE_USER_ID!, process.env.BLASTENGINE_API_KEY!);
件名・本文を用意する
続けてメール送信する内容を準備します。
const { body } = req;
const mail = new Mail();
const text = `__USERNAME__様
お問い合わせいただきありがとうございます。内容を確認し、追ってご連絡いたします。
会社名:
__COMPANY__
お名前:
__USERNAME__
お問い合わせ内容:
__MESSAGE__
`;
mail
.setFrom('info@blastengine.jp', '管理者')
.setSubject('お問い合わせありがとうございます')
.addTo(body.email, {
USERNAME: body.name,
COMPANY: body.company,
MESSAGE: body.message
})
.setText(text)
.setEncode('UTF-8');
最後にメールを送信します。レスポンスとして、blastengineから返却される配信ID(デリバリーID)を返します。
await mail.send();
res.status(200).json({ delivery_id: mail.deliveryId! });
スクリプト全体は以下のようになります。
import type { NextApiRequest, NextApiResponse } from 'next'
import { BlastEngine, Mail } from 'blastengine';
type Data = {
delivery_id: number
}
export default async function handler(
req: NextApiRequest,
res: NextApiResponse<Data>
) {
new BlastEngine(process.env.BLASTENGINE_USER_ID!, process.env.BLASTENGINE_API_KEY!);
const { body } = req;
const mail = new Mail();
const text = `__USERNAME__様
お問い合わせいただきありがとうございます。内容を確認し、追ってご連絡いたします。
会社名:
__COMPANY__
お名前:
__USERNAME__
お問い合わせ内容:
__MESSAGE__
`;
mail
.setFrom('info@blastengine.jp', '管理者')
.setSubject('お問い合わせありがとうございます')
.addTo(body.email, { USERNAME: body.name, COMPANY: body.company, MESSAGE: body.message })
.setText(text)
.setEncode('UTF-8');
await mail.send();
res.status(200).json({ delivery_id: mail.deliveryId! });
}
まとめ
今回はNext.jsとServerless Functionsを使って、お問い合わせフォームを作成しました。フロントエンドだけでなく、API実行部分もNext.js内で使えるのが便利です。