# Data Fetching
Learn how to fetch data from the Finqu Storefront API using the `@finqu/storefront-sdk`.
## Server Components
Use the Finqu SDK in Server Components for direct API access:
```tsx
// app/my-component.tsx (Server Component)
import { storefrontClient, cachePresets } from '@/lib/storefront';
import { getProduct, getCatalogProducts } from '@finqu/storefront-sdk/server';
export default async function ServerComponent() {
// Using SDK helper
const { product } = await getProduct(storefrontClient, {
handle: 'my-product-slug',
});
// Direct query
const result = await getCatalogProducts(storefrontClient, {
first: 10,
query: 'search term',
});
const products = result.catalog.products.nodes;
const totalCount = result.catalog.products.totalCount;
return
{product?.title}
;
}
```
## Client Components
Use React hooks for client-side data fetching:
```tsx
'use client';
import { useProduct, useCatalogProducts } from '@finqu/storefront-sdk/react';
export function ClientComponent() {
const { product, isLoading } = useProduct({
id: 123,
});
const { products } = useCatalogProducts({
first: 20,
query: 'shirts',
});
return {isLoading ?
Loading...
:
{product?.title}
}
;
}
```
## Caching Strategy
The SDK provides cache presets for different data types:
```tsx
import { storefrontClient, cachePresets, withLocale } from '@/lib/storefront';
// Long-lived data (1 hour)
const menus = await storefrontClient.query(MENU_QUERY, {}, withLocale('en', cachePresets.static));
// Product data (1 minute)
const products = await storefrontClient.query(PRODUCTS_QUERY, {}, cachePresets.products);
// Dynamic data (no cache)
const cart = await storefrontClient.query(CART_QUERY, {}, cachePresets.dynamic);
```
### Cache Presets
| Preset | Duration | Use Case |
| ----------- | -------- | --------------------------- |
| `static` | 1 hour | Menus, navigation, settings |
| `products` | 1 minute | Product listings, details |
| `dynamic` | No cache | Cart, user-specific data |
## Using Locale
Always pass the locale when fetching data:
```tsx
import { getLocale } from '@/lib/locale';
import { storefrontClient, withLocale } from '@/lib/storefront';
export default async function ServerComponent() {
const locale = await getLocale();
const result = await storefrontClient.query(
PRODUCTS_QUERY,
{},
withLocale(locale, cachePresets.products)
);
return {/* ... */}
;
}
```
## Error Handling
Handle API errors gracefully:
```tsx
import { storefrontClient } from '@/lib/storefront';
export default async function ServerComponent() {
try {
const { product } = await getProduct(storefrontClient, {
handle: 'my-product',
});
if (!product) {
return Product not found
;
}
return {product.title}
;
} catch (error) {
console.error('Failed to fetch product:', error);
return Error loading product
;
}
}
```
## Common Patterns
### Fetching Products
```tsx
import { getCatalogProducts } from '@finqu/storefront-sdk/server';
import { storefrontClient, cachePresets } from '@/lib/storefront';
const result = await getCatalogProducts(storefrontClient, {
first: 20,
query: 'shirts',
sortBy: 'PRICE_ASC',
});
const products = result.catalog.products.nodes;
```
### Fetching a Single Product
```tsx
import { getProduct } from '@finqu/storefront-sdk/server';
import { storefrontClient } from '@/lib/storefront';
const { product } = await getProduct(storefrontClient, {
id: 123,
// or
handle: 'product-slug',
});
```
### Fetching Categories
```tsx
import { getProductGroups } from '@finqu/storefront-sdk/server';
import { storefrontClient, cachePresets } from '@/lib/storefront';
const result = await getProductGroups(storefrontClient, {
first: 10,
});
const categories = result.catalog.productGroups.nodes;
```
## Next Steps
- [Storefront SDK Documentation](./../storefront-sdk/overview) - Full SDK reference
- [Multi-Locale Support](./multi-locale) - Handle multiple locales
- [Blocks](./blocks) - Fetch data in blocks