New Research: Supply Chain Attack on Axios Pulls Malicious Dependency from npm.Details →
Socket
Book a DemoSign in
Socket

@shopkit/data-layer

Package Overview
Dependencies
Maintainers
1
Versions
2
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@shopkit/data-layer

Enterprise data abstraction layer providing unified API for e-commerce platforms including Shopify and custom backends

latest
Source
npmnpm
Version
1.1.0
Version published
Maintainers
1
Created
Source

@shopkit/data-layer

A comprehensive, production-ready data layer package for e-commerce applications, providing unified APIs for both Shopify and custom backend integrations.

Table of Contents

  • Features
  • Installation
  • Quick Start
  • Configuration
  • API Reference
  • Usage Examples
  • Platform Support
  • Error Handling
  • Best Practices
  • Examples
  • License

Features

  • 🌐 Multi-Platform Support: Seamlessly works with both Shopify and custom backend APIs
  • ⚙️ Configurable Architecture: Zero environment variable dependencies - fully configurable through parameters
  • 🔷 TypeScript First: Built with TypeScript for complete type safety
  • 📦 Modular Design: Tree-shakable imports - use only what you need
  • 🔧 Flexible Options: Support for custom queries and variables in all API methods
  • 📋 Consistent Response Format: Standardized IResponse format across all operations
  • 🪵 Advanced Logging: Built-in logging with configurable levels and formatting
  • 🎯 Standardized Interface: All methods follow consistent signature patterns

Installation

npm install @shopkit/data-layer
# or
yarn add @shopkit/data-layer
# or
pnpm add @shopkit/data-layer

Quick Start

1. Create a Commerce Client

import { createCommerceClient, IClientConfig } from '@shopkit/data-layer';

// Shopify Client Configuration
const shopifyConfig: IClientConfig = {
  type: "shopify",
  config: {
    domain: "your-store.myshopify.com",
    storefrontAccessToken: "your-storefront-access-token",
    apiVersion: "2025-04" as const,
  },
  logging: {
    enabled: true,
    level: "info",
    prettyPrint: true,
    name: "Shopify Data Layer"
  }
};

// Custom Backend Client Configuration
const customConfig: IClientConfig = {
  type: "custom",
  config: {
    merchantId: "your-merchant-id",
    storeId: "your-store-id",
    services: {
      product: {
        apiBaseUrl: "https://api.yourstore.com/products",
      },
      order: {
        apiBaseUrl: "https://api.yourstore.com/orders",
      },
      cart: {
        apiBaseUrl: "https://api.yourstore.com/cart",
      },
    },
  },
  logging: {
    enabled: true,
    level: "info",
    prettyPrint: true,
    name: "Custom Backend Data Layer"
  }
};

// Create the client
const commerceClient = createCommerceClient(shopifyConfig);
// or
const commerceClient = createCommerceClient(customConfig);

2. Basic Usage

// Get a product
const product = await client.getProduct({ handle: "product-handle" });

if (product.success) {
  console.log(product.data);
} else {
  console.error(product.error?.message);
}

Configuration

Client Configuration Interfaces

// Shopify Configuration
interface IShopifyConfig {
  domain: string;
  storefrontAccessToken: string;
  apiVersion: string;
}

// Custom Backend Configuration
interface ICustomConfig {
  merchantId: string;
  storeId: string;
  services: {
    product: { apiBaseUrl: string };
    order: { apiBaseUrl: string };
    cart: { apiBaseUrl: string };
  };
}

// Client Configuration Union Type
type IClientConfig =
  | { type: "shopify"; config: IShopifyConfig; logging?: LoggerConfig }
  | { type: "custom"; config: ICustomConfig; logging?: LoggerConfig };

Logging Configuration

interface LoggerConfig {
  enabled: boolean;
  level: "trace" | "debug" | "info" | "warn" | "error" | "fatal";
  prettyPrint: boolean;
  name: string;
  redact?: string[];
}

Request Options

All API methods support optional configuration:

interface IOptionsRequest {
  query?: string;                    // Custom GraphQL query
  variables?: Record<string, any>;   // Custom variables
  headers?: Record<string, string>;  // Custom headers
  params?: Record<string, string>;   // URL parameters
}

API Reference

Method Signature Pattern

All methods follow this consistent pattern:

methodName(params: ISpecificRequest, options?: IOptionsRequest): Promise<IResponse>

Standardized Response Format

interface IResponse<T = any> {
  success: boolean;
  message: string;
  data?: T;
  error?: {
    message: string;
    details?: any;
  };
  meta?: IResponseMeta;
}

Product Operations

// Get single product by ID or handle
getProduct(params: ISingleProductRequest, options?: IOptionsRequest): Promise<IResponse>

interface ISingleProductRequest {
  id?: string;
  handle?: string;
}

// Get multiple products with filtering and pagination
getProducts(params: IProductQueryRequest, options?: IOptionsRequest): Promise<IResponse>

interface IProductQueryRequest {
  first?: number;
  last?: number;
  after?: string;
  before?: string;
  query?: string;
  sortKey?: string;
  reverse?: boolean;
  filters?: Array<{
    available?: boolean;
    price?: { min?: number; max?: number };
    productType?: string;
    vendor?: string;
    tag?: string;
  }>;
}

// Get multiple products by handles
getProductsByHandles(params: IProductsByHandlesRequest, options?: IOptionsRequest): Promise<IResponse>

interface IProductsByHandlesRequest {
  handles: string[];
}

Collection Operations

// Get single collection by ID or handle
getCollection(params: ISingleCollectionRequest, options?: IOptionsRequest): Promise<IResponse>

interface ISingleCollectionRequest {
  id?: string;
  handle?: string;
  productLimit?: number;
  productSortKey?: string;
  productReverse?: boolean;
  filters?: Array<{
    available?: boolean;
    price?: { min?: number; max?: number };
    productType?: string;
    vendor?: string;
    tag?: string;
  }>;
}

// Get multiple collections with filtering and pagination
getCollections(params: ICollectionQueryRequest, options?: IOptionsRequest): Promise<IResponse>

interface ICollectionQueryRequest {
  first?: number;
  last?: number;
  after?: string;
  before?: string;
  query?: string;
  sortKey?: string;
  reverse?: boolean;
}

// Get multiple collections by handles with individual query parameters
getCollectionsByHandles(params: ICollectionsByhandlesRequest, options?: IOptionsRequest): Promise<IResponse>

interface ICollectionsByhandlesRequest {
  handles: string[];
  first?: number;
  last?: number;
  after?: string;
  before?: string;
  query?: string;
  reverse?: boolean;
  sortKey?: string;
  productLimit?: number;
  productSortKey?: string;
  productReverse?: boolean;
  filters?: Array<{
    available?: boolean;
    price?: { min?: number; max?: number };
    productType?: string;
    vendor?: string;
    tag?: string;
  }>;
}

Cart Operations

// Create a new cart
createCart(options?: IOptionsRequest): Promise<IResponse>

// Get cart by ID
getCart(params: ISingleCartRequest, options?: IOptionsRequest): Promise<IResponse>

interface ISingleCartRequest {
  id: string;
}

// Update cart
updateCart(params: IUpdateCartRequest, options?: IOptionsRequest): Promise<IResponse>

interface IUpdateCartRequest {
  id: string;
  items: ICartItemRequest;
}

interface ICartItemRequest {
  productId: string;
  variantId: string;
  quantity: number;
  sellingPlanId?: string;
  attributes?: Array<{
    key: string;
    value: string;
  }>;
}

// Add items to cart
addToCart(params: IAddToCartRequest, options?: IOptionsRequest): Promise<IResponse>

interface IAddToCartRequest {
  id: string;
  items: ICartItemRequest[];
}

// Remove items from cart
removeFromCart(params: IRemoveFromCartRequest, options?: IOptionsRequest): Promise<IResponse>

interface IRemoveFromCartRequest {
  id: string;
  itemIds: string[];
}

Order Operations

// Get single order by ID (Admin only)
getOrder(params: ISingleOrderRequest, options?: IOptionsRequest): Promise<IResponse>

interface ISingleOrderRequest {
  id: string;
}

// Get multiple orders with filtering (Admin only)
getOrders(params: IOrderQueryRequest, options?: IOptionsRequest): Promise<IResponse>

interface IOrderQueryRequest {
  first?: number;
  last?: number;
  after?: string;
  before?: string;
  query?: string;
  sortKey?: string;
  reverse?: boolean;
}

// Create new order (Admin only)
createOrder(params: IOrderRequest, options?: IOptionsRequest): Promise<IResponse>

interface IOrderRequest {
  lineItems: Array<{
    variantId: string;
    quantity: number;
  }>;
  customer?: {
    email: string;
    firstName?: string;
    lastName?: string;
  };
  shippingAddress?: {
    address1: string;
    city: string;
    province: string;
    country: string;
    zip: string;
  };
}

// Update existing order (Admin only)
updateOrder(params: IUpdateOrderRequest, options?: IOptionsRequest): Promise<IResponse>

interface IUpdateOrderRequest {
  id: string;
  data: Partial<IOrderRequest>;
}

// Get customer order history
getOrderHistory(params: IOrderHistoryRequest, options?: IOptionsRequest): Promise<IResponse>

interface IOrderHistoryRequest {
  customerAccessToken: string;
  page?: number;
  limit?: number;
}

// Get specific customer order
getOrderById(params: IOrderByIdRequest, options?: IOptionsRequest): Promise<IResponse>

interface IOrderByIdRequest {
  customerAccessToken: string;
  orderId: string;
}

Customer Operations

// Get single customer by ID (Admin only)
getCustomer(params: ISingleCustomerRequest, options?: IOptionsRequest): Promise<IResponse>

interface ISingleCustomerRequest {
  id: string;
}

// Get multiple customers (Admin only)
getCustomers(params: ICustomerQueryRequest, options?: IOptionsRequest): Promise<IResponse>

// Create new customer
createCustomer(params: ICustomerRequest, options?: IOptionsRequest): Promise<IResponse>

interface ICustomerRequest {
  email: string;
  firstName?: string;
  lastName?: string;
  phone?: string;
  password?: string;
  acceptsMarketing?: boolean;
}

// Update existing customer
updateCustomer(params: IUpdateCustomerRequest, options?: IOptionsRequest): Promise<IResponse>

interface IUpdateCustomerRequest {
  id: string;
  data: Partial<ICustomerRequest>;
}

// Get customer profile (Shopify only)
getCustomerProfile(params: ICustomerProfileRequest, options?: IOptionsRequest): Promise<IResponse>

interface ICustomerProfileRequest {
  customerAccessToken: string;
}

Checkout Operations

// Create checkout
createCheckout(params: ICreateCheckoutRequest, options?: IOptionsRequest): Promise<IResponse>

interface ICreateCheckoutRequest {
  lineItems?: Array<{
    variantId: string;
    quantity: number;
  }>;
  email?: string;
  shippingAddress?: {
    address1: string;
    city: string;
    province: string;
    country: string;
    zip: string;
  };
}

Blog/Article Operations (Shopify only)

// Get single article
getArticle(params?: IGetArticleRequest, options?: IOptionsRequest): Promise<IResponse>

interface IGetArticleRequest {
  blogHandle?: string;
  articleHandle?: string;
  first?: number;
}

// Get blog articles
getBlogArticles(params: IBlogArticleRequest, options?: IOptionsRequest): Promise<IResponse>

interface IBlogArticleRequest {
  blogHandle: string;
  first?: number;
  after?: string;
}

// Get trending articles
getTrendingArticles(params: ITrendingArticleRequest, options?: IOptionsRequest): Promise<IResponse>

interface ITrendingArticleRequest {
  first?: number;
  sortBy?: string;
}

// Get article by handle
getArticleByHandle(params: IArticleByHandleRequest, options?: IOptionsRequest): Promise<IResponse>

interface IArticleByHandleRequest {
  blogHandle: string;
  articleHandle: string;
}

Utility Operations

// Custom GraphQL request (Shopify only)
graphqlRequest(params: IGraphqlRequest): Promise<IResponse>

interface IGraphqlRequest {
  query: string;
  variables?: Record<string, any>;
}

// Custom HTTP fetch request
fetchRequest(params: IFetchRequest): Promise<IResponse>

interface IFetchRequest {
  url: string;
  method?: string;
  headers?: Record<string, string>;
  body?: string;
  signal?: AbortSignal;
  [key: string]: any;
}

Usage Examples

Product Operations

// Get single product
const product = await client.getProduct({ handle: "product-handle" });

// Get single product with custom headers
const product = await client.getProduct(
  { handle: "product-handle" },
  { headers: { "X-Custom-Header": "value" } }
);

// Get multiple products
const products = await client.getProducts({
  first: 20,
  query: "shirt",
  sortKey: "TITLE"
});

// Get products by handles
const products = await client.getProductsByHandles({
  handles: ["handle1", "handle2"]
});

Collection Operations

// Get single collection
const collection = await client.getCollection({ handle: "collection-handle" });

// Get multiple collections
const collections = await client.getCollections({ first: 10 });

// Get collections by handles with shared parameters
const collections = await client.getCollectionsByHandles({
  handles: ["featured-products", "sale-items", "new-arrivals"],
  first: 10,
  productLimit: 20,
  filters: [{ available: true }]
});

Cart Operations

// Create cart
const cart = await client.createCart();

// Get cart
const cart = await client.getCart({ id: "cart-id" });

// Add items to cart
const updatedCart = await client.addToCart({
  id: "cart-id",
  items: [
    {
      productId: "product-id",
      variantId: "variant-id",
      quantity: 1
    }
  ]
});

// Update cart
const updatedCart = await client.updateCart({
  id: "cart-id",
  data: {
    items: [
      {
        productId: "product-id",
        variantId: "variant-id",
        quantity: 2
      }
    ]
  }
});

// Remove items from cart
const updatedCart = await client.removeFromCart({
  id: "cart-id",
  itemIds: ["line-id"]
});

Order Operations

// Get order history
const orders = await client.getOrderHistory({
  customerAccessToken: "customer-access-token",
  page: 1,
  limit: 10
});

// Get specific order
const order = await client.getOrderById({
  customerAccessToken: "customer-access-token",
  orderId: "order-id"
});

Framework Integration Examples

Next.js App Router (Server-Side)

// app/products/[handle]/page.tsx
import { createCommerceClient } from '@shopkit/data-layer';

export default async function ProductPage({ params }: { params: { handle: string } }) {
  const client = createCommerceClient(shopifyConfig);
  
  const response = await client.getProduct({ handle: params.handle });
  
  if (!response.success) {
    return <div>Error: {response.error?.message}</div>;
  }
  
  const product = response.data;
  
  return (
    <div>
      <h1>{product.title}</h1>
      <p>{product.description}</p>
      <div>Price: {product.priceRange.minVariantPrice.amount} {product.priceRange.minVariantPrice.currencyCode}</div>
    </div>
  );
}

API Route Usage

// app/api/products/route.ts
import { NextRequest } from 'next/server';
import { createCommerceClient } from '@shopkit/data-layer';

export async function GET(request: NextRequest) {
  const { searchParams } = new URL(request.url);
  const client = createCommerceClient(shopifyConfig);
  
  const response = await client.getProducts({
    first: 10,
    query: searchParams.get('query') || undefined
  });
  
  return Response.json(response);
}

Client-Side Usage

'use client';

import { useState, useEffect } from 'react';
import { IResponse } from '@shopkit/data-layer';

export function useProducts(query?: string) {
  const [response, setResponse] = useState<IResponse | null>(null);
  const [loading, setLoading] = useState(true);
  
  useEffect(() => {
    async function fetchProducts() {
      try {
        const res = await fetch(`/api/products?query=${query || ''}`);
        const data = await res.json();
        setResponse(data);
      } catch (error) {
        setResponse({
          success: false,
          message: 'Failed to fetch products',
          error: { message: error instanceof Error ? error.message : 'Unknown error' }
        });
      } finally {
        setLoading(false);
      }
    }
    
    fetchProducts();
  }, [query]);
  
  return { response, loading };
}

Platform Support

Shopify Adapter

  • Products: Full support for product operations
  • Collections: Full support for collection operations
  • Cart: Full cart management
  • Orders: Customer order history and details
  • Blog: Article and blog operations
  • GraphQL: Custom GraphQL queries
  • Customer: Customer profile access

Custom Backend Adapter

  • Products: Full support for product operations
  • Collections: Full support for collection operations
  • Cart: Full cart management
  • Orders: Customer order history and details
  • Checkout: Basic checkout creation
  • Blog: Not implemented
  • GraphQL: Not available

Method Support Matrix

MethodCustom AdapterShopify AdapterNotes
Product Operations
getProduct✅ Implemented✅ ImplementedCore product retrieval
getProducts✅ Implemented✅ ImplementedProduct listing with filters
getProductsByHandles✅ Implemented✅ ImplementedBatch product retrieval
Collection Operations
getCollection✅ Implemented✅ ImplementedSingle collection retrieval
getCollections✅ Implemented✅ ImplementedCollection listing
getCollectionsByHandles✅ Implemented✅ ImplementedBatch collection retrieval
Order Operations
getOrder❌ (Error thrown)❌ (NotImplemented)Single order retrieval
getOrders❌ (Error thrown)❌ (NotImplemented)Order listing
createOrder❌ (Error thrown)❌ (NotImplemented)Order creation
updateOrder❌ (Error thrown)❌ (NotImplemented)Order updates
getOrderHistory✅ Implemented✅ ImplementedCustomer order history
getOrderById✅ Implemented✅ ImplementedCustomer specific order
Customer Operations
getCustomer❌ (Error thrown)❌ (NotImplemented)Single customer retrieval
getCustomers❌ (Error thrown)❌ (NotImplemented)Customer listing
createCustomer❌ (Error thrown)❌ (NotImplemented)Customer creation
updateCustomer❌ (Error thrown)❌ (NotImplemented)Customer updates
getCustomerProfile❌ (Not available)✅ ImplementedShopify-specific method
Cart Operations
getCart✅ Implemented✅ ImplementedCart retrieval
createCart✅ Implemented✅ ImplementedCart creation
updateCart✅ Implemented✅ ImplementedCart updates
addToCart✅ Implemented✅ ImplementedAdd items to cart
removeFromCart✅ Implemented✅ ImplementedRemove items from cart
Checkout Operations
createCheckout✅ Implemented❌ (NotImplemented)Checkout creation
Article/Blog Operations
getArticle❌ (NotImplemented)✅ ImplementedSingle article retrieval
getBlogArticles❌ (NotImplemented)✅ ImplementedBlog article listing
getTrendingArticles❌ (NotImplemented)✅ ImplementedTrending articles
getArticleByHandle❌ (NotImplemented)✅ ImplementedArticle by handle
Utility Operations
graphqlRequest❌ (NotImplemented)✅ ImplementedGraphQL utility
fetchRequest✅ Inherited✅ InheritedHTTP fetch utility

Error Handling

The data layer provides comprehensive error handling:

const response = await client.getProduct({ handle: "invalid-handle" });

if (!response.success) {
  console.error("Error:", response.error?.message);
  
  // Handle specific error types
  if (response.error?.details?.name === "NotFoundError") {
    // Handle product not found
  }
}

Best Practices

  • Always check response.success before accessing data
  • Use TypeScript for full type safety and better developer experience
  • Enable logging during development for better debugging
  • Handle errors gracefully with proper fallbacks
  • Use environment variables for sensitive configuration data
  • Implement proper caching for frequently accessed data
  • Use custom queries sparingly and only when standard methods are insufficient
  • Follow the standardized method signature pattern for consistency

Examples

For complete examples and usage patterns, see the data layer example app.

Data Layer Example App Features

The example application includes several user experience improvements:

Enhanced JSON Input Fields

The example app provides improved textarea formatting for complex JSON payloads:

  • Add to Cart: Multi-line textarea with formatted JSON structure for items array
  • Update Cart: Enhanced textarea for cart item modifications with proper formatting
  • Create Checkout: Improved textarea for checkout payload with correct interface structure

Example Add to Cart Payload Format:

[
  {
    "productId": "gid://shopify/Product/123",
    "variantId": "gid://shopify/ProductVariant/123",
    "quantity": 1,
    "sellingPlanId": "selling-plan-id",
    "attributes": [
      {
        "key": "gift-wrap",
        "value": "true"
      }
    ]
  }
]

Example Create Checkout Payload Format:

{
  "cart_token": "cart-token-here",
  "checkout_id": "checkout-id-here",
  "attributes": {
    "email": "customer@example.com",
    "note": "Special instructions",
    "phone": "+1234567890",
    "custom_field": "custom_value"
  }
}

These improvements provide:

  • Better Readability: Multi-line JSON with proper indentation
  • Larger Input Areas: Textarea fields instead of single-line inputs
  • Complete Examples: Shows all available fields and proper structure
  • Error Prevention: Properly formatted examples reduce JSON syntax errors

License

MIT License - see the LICENSE file for details.

Keywords

data-layer

FAQs

Package last updated on 23 Feb 2026

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts