はじめに
ヘッドレスE-commerceアーキテクチャにおいて、ShopifyのバックエンドとNext.jsのフロントエンドを統合することは、スケーラブルで高性能なオンラインストアを構築するための基盤です。この第2部では、Shopify Storefront APIとAdmin APIを活用し、Next.jsプロジェクトをセットアップしてGraphQLでデータフェッチを行う方法を解説します。Vercelを使ったデプロイも含め、開発者向けにAPI統合と環境構築の詳細を提供します。パフォーマンスと拡張性を重視した実践的なアプローチを、コードスニペットとともに紹介します。
開発環境のセットアップ
効率的な開発には、適切な環境構築が不可欠です。以下は、ShopifyとNext.jsを使用するための準備手順です。
1. Shopifyストアの準備
Shopify開発ストアを作成し、API認証情報を取得します。
# Shopify開発ストアの作成
1. Shopify Partnerアカウントにログイン
2. 「ストア」→「開発ストアの追加」を選択
3. ストア名(例:my-ecommerce-dev)を入力
4. Storefront APIトークンを生成:
- 「アプリ」→「アプリを管理」→「プライベートアプリを作成」
- Storefront APIを有効化し、トークンをコピー
5. Admin APIトークンを取得(在庫や注文管理用)
- Admin APIスコープを有効化(products, ordersなど)
環境変数の例(.env.local
):
SHOPIFY_STOREFRONT_API_TOKEN=shpat_xxxxxxxxxxxxxxxxxxxx
SHOPIFY_ADMIN_API_TOKEN=shpua_xxxxxxxxxxxxxxxxxxxx
SHOPIFY_STOREFRONT_API_ENDPOINT=https://my-ecommerce-dev.myshopify.com/api/2025-07/graphql.json
2. Next.jsプロジェクトの初期化
Next.jsプロジェクトをTypeScriptとTailwind CSSでセットアップします。
# Next.jsプロジェクトの作成
1. npx create-next-app@latest --ts my-ecommerce
2. cd my-ecommerce
3. npm install @shopify/storefront-api-client @apollo/client graphql tailwindcss postcss autoprefixer
4. npx tailwindcss init -p
Tailwind CSSの設定(tailwind.config.js
):
module.exports = {
content: [
"./pages/**/*.{js,ts,jsx,tsx}",
"./components/**/*.{js,ts,jsx,tsx}",
],
theme: {
extend: {},
},
plugins: [],
}
CSS初期化(styles/globals.css
):
@tailwind base;
@tailwind components;
@tailwind utilities;
3. Apollo Clientの設定
Apollo Clientを統合して、GraphQLクエリを効率的に管理します。
# Apollo Clientの依存関係
npm install @apollo/client graphql
Apollo Clientの初期化(lib/apollo-client.ts
):
import { ApolloClient, InMemoryCache, createHttpLink } from '@apollo/client';
const httpLink = createHttpLink({
uri: process.env.SHOPIFY_STOREFRONT_API_ENDPOINT,
headers: {
'X-Shopify-Storefront-Access-Token': process.env.SHOPIFY_STOREFRONT_API_TOKEN,
},
});
export const client = new ApolloClient({
link: httpLink,
cache: new InMemoryCache(),
});
Shopify Storefront APIの統合
Shopify Storefront APIを使用し、商品データやコレクションを取得します。以下は、商品リストを取得するサンプルクエリです。
1. 商品データのフェッチ
Next.jsのgetStaticPropsで商品データを取得:
// pages/index.tsx
import { GetStaticProps } from 'next';
import { gql } from '@apollo/client';
import { client } from '../lib/apollo-client';
const GET_PRODUCTS = gql`
query GetProducts($first: Int!) {
products(first: $first) {
edges {
node {
id
title
handle
priceRange {
minVariantPrice {
amount
currencyCode
}
}
images(first: 1) {
edges {
node {
src
altText
}
}
}
}
}
}
}
`;
export const getStaticProps: GetStaticProps = async () => {
const { data } = await client.query({
query: GET_PRODUCTS,
variables: { first: 10 },
});
return {
props: {
products: data.products.edges.map(({ node }: { node: any }) => node),
},
revalidate: 60, // ISR: 60秒ごとに再生成
};
};
export default function Home({ products }: { products: any[] }) {
return (
<div className="container mx-auto p-4">
<h1 className="text-3xl font-bold mb-6">商品リスト</h1>
<div className="grid grid-cols-3 gap-4">
{products.map((product) => (
<div key={product.id} className="border p-4 rounded">
<img src={product.images.edges[0]?.node.src} alt={product.images.edges[0]?.node.altText} className="w-full h-48 object-cover" />
<h2 className="text-xl font-semibold">{product.title}</h2>
<p>{product.priceRange.minVariantPrice.amount} {product.priceRange.minVariantPrice.currencyCode}</p>
</div>
))}
</div>
</div>
);
}
このコードは、**Incremental Static Regeneration (ISR)**を使用して、商品データを静的に生成しつつ、定期的に更新します。
2. コレクションの取得
カテゴリ(コレクション)データを取得するクエリ例:
query GetCollections($first: Int!) {
collections(first: $first) {
edges {
node {
id
title
handle
products(first: 5) {
edges {
node {
id
title
}
}
}
}
}
}
}
Next.jsのdynamic routesでコレクションごとのページを生成:
// pages/collections/[handle].tsx
import { GetStaticPaths, GetStaticProps } from 'next';
import { gql } from '@apollo/client';
import { client } from '../../lib/apollo-client';
const GET_COLLECTION = gql`
query GetCollection($handle: String!) {
collection(handle: $handle) {
id
title
products(first: 10) {
edges {
node {
id
title
handle
priceRange {
minVariantPrice {
amount
currencyCode
}
}
}
}
}
}
}
`;
export const getStaticPaths: GetStaticPaths = async () => {
const { data } = await client.query({
query: gql`
query GetCollectionHandles {
collections(first: 10) {
edges {
node {
handle
}
}
}
}
`,
});
const paths = data.collections.edges.map(({ node }: { node: any }) => ({
params: { handle: node.handle },
}));
return { paths, fallback: 'blocking' };
};
export const getStaticProps: GetStaticProps = async ({ params }) => {
const { data } = await client.query({
query: GET_COLLECTION,
variables: { handle: params?.handle },
});
return {
props: { collection: data.collection },
revalidate: 60,
};
};
export default function CollectionPage({ collection }: { collection: any }) {
return (
<div className="container mx-auto p-4">
<h1 className="text-3xl font-bold mb-6">{collection.title}</h1>
<div className="grid grid-cols-3 gap-4">
{collection.products.edges.map(({ node }: { node: any }) => (
<div key={node.id} className="border p-4 rounded">
<h2 className="text-xl font-semibold">{node.title}</h2>
<p>{node.priceRange.minVariantPrice.amount} {node.priceRange.minVariantPrice.currencyCode}</p>
</div>
))}
</div>
</div>
);
}
このコードは、コレクションごとの動的ページを生成し、SEOとパフォーマンスを最適化します。
Vercelでのデプロイ
Vercelを使用して、プロジェクトをグローバルにデプロイします。
# Vercelデプロイ手順
1. npm install -g vercel
2. cd my-ecommerce
3. vercel
4. 環境変数を設定:
- SHOPIFY_STOREFRONT_API_TOKEN
- SHOPIFY_STOREFRONT_API_ENDPOINT
5. ドメインを割り当て(例:my-ecommerce.vercel.app)
6. 自動スケーリングとエッジキャッシュを有効化
Vercel設定例(vercel.json
):
{
"framework": "nextjs",
"builds": [
{
"src": "package.json",
"use": "@vercel/next"
}
],
"env": {
"SHOPIFY_STOREFRONT_API_ENDPOINT": "@shopify_storefront_api_endpoint",
"SHOPIFY_STOREFRONT_API_TOKEN": "@shopify_storefront_api_token"
}
}
テストとデバッグ
統合後、以下のテストを実施:
- APIテスト: GraphQLクエリのレスポンス時間(目標:200ms以下)。
- データ整合性: 商品データが正しくレンダリングされるか。
- デプロイ確認: Vercelでページが正常に表示されるか。
- エラーハンドリング: 無効なAPIトークンやクエリエラーの処理。
Apollo Clientのエラーハンドリング例:
// lib/apollo-client.ts
import { ApolloClient, InMemoryCache, createHttpLink } from '@apollo/client';
import { onError } from '@apollo/client/link/error';
const errorLink = onError(({ graphQLErrors, networkError }) => {
if (graphQLErrors) {
graphQLErrors.forEach(({ message }) => console.error(`[GraphQL error]: ${message}`));
}
if (networkError) console.error(`[Network error]: ${networkError}`);
});
const httpLink = createHttpLink({
uri: process.env.SHOPIFY_STOREFRONT_API_ENDPOINT,
headers: {
'X-Shopify-Storefront-Access-Token': process.env.SHOPIFY_STOREFRONT_API_TOKEN,
},
});
export const client = new ApolloClient({
link: errorLink.concat(httpLink),
cache: new InMemoryCache(),
});
まとめ
この第2部では、ShopifyとNext.jsを使ったヘッドレスE-commerceの環境構築とStorefront APIの統合を解説しました。GraphQLとApollo Clientを活用し、Vercelでデプロイすることで、スケーラブルな基盤を構築しました。次の第3部では、Next.jsとTailwind CSSを使ったUI設計を掘り下げます。
Qiitaの皆さん、この記事が役に立ったら「いいね」や「ストック」をお願いします!コメントで技術的な質問や提案もお待ちしています!