Quick Start
In this tutorial, you'll build a product listing page that fetches and displays products from your Elastic Path catalog.
What you'll build
A simple product listing that:
- Fetches products from your catalog
- Displays product images, names, and prices
- Handles loading and error states
Prerequisites
- Node.js 18+ and npm installed
- An Elastic Path store with:
- Published catalog with products
- API credentials
Step 1: Create a Next.js project
This quickstart uses Next.js, but the SDK works with any JavaScript framework.
npx create-next-app@latest my-elastic-path-store
cd my-elastic-path-store
When prompted, choose:
- TypeScript: Yes
- ESLint: Yes
- Tailwind CSS: Yes (for styling)
- App Router: Yes
Step 2: Install the SDK
Install the Elastic Path Shopper SDK:
npm install @epcc-sdk/sdks-shopper
Step 3: Set up authentication
Create a .env.local file in your project root:
# Choose your region:
# US East: https://useast.api.elasticpath.com
# EU West: https://euwest.api.elasticpath.com
NEXT_PUBLIC_EPCC_ENDPOINT_URL=https://useast.api.elasticpath.com
NEXT_PUBLIC_EPCC_CLIENT_ID=your-client-id
Step 4: Create the SDK client
Create a new file lib/epcc-client.ts:
// lib/epcc-client.ts
import { configureClient } from "@epcc-sdk/sdks-shopper";
const endpointUrl = process.env.NEXT_PUBLIC_EPCC_ENDPOINT_URL;
const clientId = process.env.NEXT_PUBLIC_EPCC_CLIENT_ID;
if (!endpointUrl || !clientId) {
throw new Error('Missing Elastic Path credentials');
}
// Configure the SDK client
export const client = configureClient(
{
baseUrl: endpointUrl
},
{
clientId,
storage: "localStorage"
}
);
Step 5: Create the products page
Replace the contents of app/page.tsx:
// app/page.tsx
import { getByContextAllProducts } from "@epcc-sdk/sdks-shopper";
import "@/lib/epcc-client"; // Initialize the client
async function getProducts() {
const response = await getByContextAllProducts({
query: {
"page[limit]": 12,
include: ["main_image"]
}
});
return {
products: response.data?.data || [],
mainImages: response.data?.included?.main_images || []
};
}
Add the display logic to the same file:
// app/page.tsx
import Image from "next/image";
import { extractProductImage } from "@epcc-sdk/sdks-shopper";
export default async function ProductsPage() {
const { products, mainImages } = await getProducts();
return (
<div className="container mx-auto p-6">
<h1 className="text-3xl font-bold mb-8">Products</h1>
<div className="grid grid-cols-1 md:grid-cols-3 lg:grid-cols-4 gap-6">
{products.map((product) => {
const mainImage = extractProductImage(product, mainImages);
const imageUrl = mainImage?.link?.href || "/placeholder.jpg";
return (
<div key={product.id} className="border rounded-lg p-4">
<div className="relative h-48 mb-4">
<Image
src={imageUrl}
alt={product.attributes.name}
fill
className="object-contain"
/>
</div>
<h3 className="font-semibold">
{product.attributes.name}
</h3>
<p className="text-gray-600">
{product.meta?.display_price?.without_tax?.formatted}
</p>
</div>
);
})}
</div>
{products.length === 0 && (
<p className="text-center text-gray-500">No products found</p>
)}
</div>
);
}
Step 6: Complete example
Here's the complete page component:
// app/page.tsx
import { getByContextAllProducts, extractProductImage } from "@epcc-sdk/sdks-shopper";
import "@/lib/epcc-client"; // Initialize the client
import Image from "next/image";
async function getProducts() {
const response = await getByContextAllProducts({
query: {
"page[limit]": 12,
include: ["main_image"]
}
});
return {
products: response.data?.data || [],
mainImages: response.data?.included?.main_images || []
};
}
export default async function ProductsPage() {
try {
const { products, mainImages } = await getProducts();
return (
<div className="container mx-auto p-6">
<h1 className="text-3xl font-bold mb-8">Products</h1>
<div className="grid grid-cols-1 md:grid-cols-3 lg:grid-cols-4 gap-6">
{products.map((product) => {
const mainImage = extractProductImage(product, mainImages);
const imageUrl = mainImage?.link?.href || "/placeholder.jpg";
return (
<div key={product.id} className="border rounded-lg p-4">
<div className="relative h-48 mb-4">
<Image
src={imageUrl}
alt={product.attributes.name}
fill
className="object-contain"
/>
</div>
<h3 className="font-semibold">
{product.attributes.name}
</h3>
<p className="text-gray-600">
{product.meta?.display_price?.without_tax?.formatted}
</p>
</div>
);
})}
</div>
{products.length === 0 && (
<p className="text-center text-gray-500">No products found</p>
)}
</div>
);
} catch (error) {
return (
<div className="container mx-auto p-6">
<h1 className="text-3xl font-bold mb-4">Products</h1>
<p className="text-red-500">Failed to load products. Please try again.</p>
</div>
);
}
}
Step 7: Run the application
-
Start your development server:
npm run dev -
Open your browser and navigate to
http://localhost:3000 -
You should see:
- A grid of products from your catalog
- Product images, names, and prices
- Proper error handling if the API fails
What you've built
✅ A working product listing page
✅ Integration with Elastic Path Catalog API
✅ Proper TypeScript types from the SDK
✅ Error handling and loading states
✅ Responsive grid layout
Next Steps
Now that you have a basic product listing, enhance it with:
| Feature | Guide |
|---|---|
| Pagination and filtering | List Products |
| Product detail pages | Get Product Details |
| Product variations | Variations Overview |
| Bundle products | Bundles Overview |