Next.jsワークショップやってみた③外部連携編
参考サイト:Stripeを利用して、商品・料金情報を登録しよう – Zenn
決済サービスStripeの設定
- アカウント作成:メールアドレス、名前で登録できます。
- 店舗のアカウント作成:店舗の名前を入力します。
- 商品登録:商品名、説明、画像、価格を登録します。
- クロスセル(関連商品):コーヒー豆にコーヒードリッパーを関連づけます。
APIでデータ取得
APIキー
キーの種類 | 用途 |
---|---|
公開キー | フロントエンドアプリで、カードのtoken化などに利用する。 |
シークレットキー | Stripeの公開しているAPI全てにアクセスができるAPIで、万が一漏洩した場合には顧客情報や注文データなどを取得されるリスクが生じる。 |
制限付きのキー | アクセスできるリソースや操作を個別に設定することができる。 |
今回は必要最低限の権利を付与した制限付きキーを作ります。
リソースタイプ | 権限 |
---|---|
Products | 読み取り |
Prices | 読み取り |
Checkout Sessions | 書き込み |
それ以外 | なし |
次に、Next.jsにAPIキーを設定します。
STRIPE_API_KEY=rk_test_xxxxx
NEXT_PUBLIC_STRIPE_PUBLISHABLE_API_KEY=pk_test_xxxxxx
- STRIPE_API_KEY:制限付きキー
- NEXT_PUBLIC_STRIPE_PUBLISHABLE_API_KEY:公開キー
フロントエンドで使うものには「NEXT_PUBLIC_」を付けますが、第三者に見られたくない値には付けないように注意が必要だそうです。
Stripe SDKをインストールする
npm install stripe
package.json
のdependencies
にstripeが追加されます。
"dependencies": {
...
"stripe": "^16.12.0"
},
APIの実装
pages/api/products.tsに追記します。
Stripe SDKでは、
new Stripe()
の戻り値に顧客や商品・料金などのリソースへアクセスするプロパティが含まれています。商品の一覧を取得するには、
Zennstripe.products.list()
を利用します。
https://docs.stripe.com/api/products/list
import Stripe from "stripe";
...
const stripe = new Stripe(process.env.STRIPE_API_KEY ?? "", {
maxNetworkRetries: 3 // ネットワークエラーでStripe API呼び出しが失敗した時のリトライ回数を指定
})
【エラー小話】型 ‘string | undefined’ の引数を型 ‘string’ のパラメーターに割り当てることはできません。
【Typescript】型 ‘string | undefined’ の引数を ‘string’ のパラメーターに割り当てることができません。を解決したい – Qiita
→ 「?? “”」を追記。「envを読み込むタイミングで型の絞り込み(narrowing)をします」と解説されていましたが、まだ難しくて分かっていません。
async/awaitでデータ取得
before
export default function handler(req: NextApiRequest, res: NextApiResponse) {
after
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
before
res.status(200).json(
[
{
name: "サバ缶",
price: 150,
},
{
name: "ツナ缶",
price: 300,
}
]
)
after
const products = await stripe.products.list()
res.status(200).json(products)
curlコマンドで確認する場合
以下のコマンドを実行します。
% curl http://localhost:3000/api/products
{"object":"list","data":[{"id":"prod_QsNcmlcynzeNFB","object":"product","active":true,"attributes":[],"created":1726723479,"default_price":"price_1Q0cr5Ap7bPBQwOfQcVxoBmr","description":"産地直送のとうもろこしです。"...
必要なデータだけ表示する
pages/api/products.ts
before:とりあえず取得したデータを全てJSONで表示しています。
const products = await stripe.products.list()
res.status(200).json(products)
after:データ取得後、JSONを整形しています。また、料金情報を取得するためawait stripe.prices.list()で別途APIリクエストをしています。
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
...
const response = await Promise.all(products.data.map(async (product, i) => {
const prices = await stripe.prices.list({
product: product.id,
})
return {
id: product.id,
description: product.description,
name: product.name,
images: product.images,
unit_label: product.unit_label,
prices: prices.data.map(price => {
return {
id: price.id,
currency: price.currency,
transform_quantitiy: price.transform_quantity,
unit_amount: price.unit_amount,
}
})
}
}))
res.status(200).json(response)
}