Nuxt3でShopifyのCheckoutIDが付与されたURLにリダレクト処理を行う
  • 2022.03.18に公開
  • Nuxt3
  • 1. Shopify APIとの連携
  • No.4 / 5
現在このカテゴリーは、Nuxt3パブリックベータ版の情報を公開しています。変更の可能性が大きくあるので、最新の情報は Nuxt3の公式サイト をご確認ください。

ShopifyのCheckout IDとは?

ShopifyのCheckout IDとは、カートの中身や顧客情報を保持できるトークンです。

主にURLのクエリに付与されます。

このCheckout IDが付与されたURLを覚えておけば、ユーザーがページを離脱してもカートの中身を保持できます。

2022-03-18 09-39-45

Checkout IDをクエリに付与する実装法

Checkout IDは常にURLクエリに付与されていなければなりません。

そこで、ユーザーが初めてサイトに訪れた時に

  • Checkout IDの発行
  • URLクエリへ添付
  • そのURLへリダイレクトする

実装を行います。

リダイレクト処理を実行するファイル

実装ファイルは「plugins」ディレクトリ以下に作成します。

Nuxtの「plugins」ディレクトリは、Nuxtインスタンス生成直後に1度だけ呼ばれます。

この仕組みを利用すれば、ユーザーが初めてサイトに訪れたときに、Checkout IDが付与したURLにリダイレクト処理を行うことができます。

後は発行したCheckout IDをクエリに付与しページ遷移を行えばOKです。

Shopify初期化ファイルをpluginsに移動する

Nuxt3では、「server/api」以下のファイルをインポートしようとするとエラーを吐きます。

こちらの記事で解説 importする自作プラグインはserver/apiには置けない

そこで前回作成したShopifyの初期化ファイル、

  • server/api/shopify/client.tsを => plugins/shopify.server.ts

移動します。

まずpluginsディレクトリを作成しましょう。

% mkdir plugins

コードは同じなので、ファイルをshopify.server.tsにリネームして「plugins」に移動します。

% mv server/api/shopify/client.ts plugins/shopify.server.ts

Shopifyの初期化プラグインが作成できました。

plugins/shopify.server.ts
import Client from 'shopify-buy'

const client = Client.buildClient({
  domain: process.env.SHOPIFY_DOMAIN,
  storefrontAccessToken: process.env.SHOPIFY_ACCESS_TOKEN,
  language: 'ja-JP'
})

export default client

Nuxt3でサーバーサイドプラグインを作成する方法

Nuxt3では、サーバーサイドのみで稼働するプラグインファイルに.serverを付けます。

Nuxtはpluginsディレクトリにあるファイルを自動的に読み込んでロードします。

ファイル名に .server または .client というサフィックスを使用すると、サーバ側またはクライアント側でのみプラグインをロードすることができます。

引用: Nuxt 3 - Plugins directory

補足として、nuxt.config.jspluginsプロパティに登録しなくても自動で読み込まれます。

「plugins」ディレクトリに作成したファイルは、デフォルトでサーバーとクライアントで呼ばれます。

今回のアプリでは、漏洩を防ぐためShopifyのアクセストークンをサーバーサイドでのみ参照する仕様としています。

ですのでプラグインファイルもサーバーのみで読み込まれる必要があるため、.serverファイルとしています。

Shopify Clientのインポート文を変更する

「server/api/shopify」ディレクトリ以下の

  • get-product.ts
  • get-products.ts

import文を変更します。

server/api/shopify/get-product.ts & get-products.ts
// import先を変更
// import client from './client'
import client from '~/plugins/shopify.server'

これで下準備が整いました。

Checkout IDにリダイレクトする処理を実行

新たなサーバーサイドプラグインを作成します。

% touch plugins/redirect-checkout.server.ts

redirect-checkout.server.tsには、URLクエリにCheckout IDが存在しない場合、クエリをつけたURLにリダイレクトを行います。

Shopify APIでCheckout ID を発行するにはcheckout.create()メソッドを使用します。

await client.checkout.create()
 .then(checkout => console.log(checkout.id))

それではリダイレクト処理を記述しましょう。

plugins/redirect-checkout.server.ts
import client from '~/plugins/shopify.server'
import Url from 'url'

type CheckoutId = string | number | string[]

export default defineNuxtPlugin(async (nuxtApp) => {
  console.log('plugins/redirect-checkout.server.ts')

  const url = Url.parse(nuxtApp.ssrContext.req.url, true)
  let checkoutId: CheckoutId = url.query.checkoutId

  // checkoutIdが存在する場合は処理を終了する
  if (checkoutId) {
    return
  }

  const pathname: string = url.pathname

  await client.checkout.create()
    .then(checkout => (checkoutId = checkout.id))

  console.log('checkoutId', checkoutId)

  // $router.replaceでリダイレクトした後もサーバーサイドプラグインは読み込まれるため、実質処理は2回走る
  nuxtApp.$router.replace({
    path: pathname,
    query: { checkoutId }
  })

  console.log('----------------------------------')
})
  • let checkoutId: CheckoutId = url.query.checkoutId ... URLからクエリを取得。
  • const pathname: string = url.pathname ... ユーザーがアクセスしようとしたパスを取得。
  • $router.replace ... クエリを付与してアクセスURLにリダイレクト処理。
    • replace ... URLの履歴を残さずページ遷移を行う。URLの履歴とは、クエリ添付前のURLのこと。

クエリを付与してリダイレクトを行うとフルパスが変更されるので、もう一度サーバーサイドプラグインが読み込まれます。

実質、redirect-checkout.server.tsは2回読み込まれます。

Url.parse(nuxtApp.ssrContext.req.url, true)

ユーザーがアクセスしようとしたURLをサーバーで取得し、Urlライブラリを使用してオブジェクトに変換しています。

const urlの実態は以下の通りです。

urlオブジェクトの実態
const url = Url.parse(nuxtApp.ssrContext.req.url, true)
console.log(url)

// console
Url {
  protocol: null,
  slashes: null,
  auth: null,
  host: null,
  port: null,
  hostname: null,
  hash: null,
  search: null,
  query: [Object: null prototype] {},
  pathname: '/',
  path: '/',
  href: '/'
}

awaitの後にnavigateToが発火しない?

navigateToは、Nuxt3が用意しているリダイレクトを行うメソッドです。

navigateTo (route: string | Route)

プラグインやミドルウェア内で、指定されたルートへリダイレクトします。また、ページナビゲーションを行うために、クライアントサイドで直接呼び出すこともできます

引用: Nuxt 3 - Middleware directory

Nuxt3のデフォルトの挙動なのか、私のコードが悪いのか?

awaitの後にnavigateToを実行してもスルーします。

await client.checkout.create()
  .then(checkout => (checkoutId = checkout.id))

// 実行されない
navigateTo({ 
  path: pathname,
  query: { checkoutId: checkoutId || 'aaa' } 
})

awaitを介さない処理の後は実行されることを確認しました。

ただこの場合、checkout.create()の処理を終わるのを待たずにリダイレクト処理が実行されるので使い物になりません。

client.checkout.create()
  .then(checkout => (checkoutId = checkout.id))

// 実行されるがcheckoutIdは発行されていないため、'aaa'が付与される
navigateTo({ 
  path: pathname,
  query: { checkoutId: checkoutId || 'aaa' } 
})

対応

navigateToの実態は、VueRouterを使用してリダイレクトをおこなっています。

そこで、Nuxtインスタンスの$rouer.replaceでリダイレクト処理を行いました。

await client.checkout.create()
	.then(checkout => (checkoutId = checkout.id))

nuxtApp.$router.replace({
  path: pathname,
  query: { checkoutId }
})

ブラウザで確認しよう

http://localhost:3000/の状態でページをリロードしてください。

Checkout IDクエリが付与されたURLにリダイレクトされました。

2022-03-18 23-28-31

実装は以上です。

まとめ

今回はShopifyのカート情報を保持するCheckout IDを、URLクエリにつけてリダイレクトを行う実装をしました。

このCheckout IDを常にURLに付与することで、どのページに遷移しても、サイトを離脱してもカートの中身を保持することができます。

また決済時には、このCheckout IDをShopify渡すことでカート情報を共有します。

ここら辺の実装はまだ調査中なので、分かり次第ここで共有します。それでは!

あなたの力になれること
私自身が独学でプログラミングを勉強してきたので、一人で学び続ける苦しみは痛いほど分かります。そこで、当時の私がこんなのあったら良いのにな、と思っていたサービスを立ち上げました。周りに質問できる人がいない、答えの調べ方が分からない、ここを聞きたいだけなのにスクールは高額すぎる。そんな方に向けた単発・短期間メンターサービスを行っています。
独学プログラマのサービス
独学プログラマ
独学でも、ここまでできるってよ。
CONTACT
Nuxt.js制作のご依頼は下記メールアドレスまでお送りください。