Files
2026-03-07 11:07:45 -03:00

392 lines
13 KiB
Markdown

# Connecting to Backend
## Contents
- [Overview](#overview)
- [Detecting the Backend](#detecting-the-backend-critical)
- [Framework Detection](#framework-detection)
- [Environment Configuration](#environment-configuration)
- [Backend-Specific Integration](#backend-specific-integration)
- [Authentication Patterns](#authentication-patterns)
- [Cart State Management](#cart-state-management)
- [Error Handling for Ecommerce](#error-handling-for-ecommerce)
- [Performance Patterns](#performance-patterns)
- [Data Fetching with TanStack Query](#data-fetching-with-tanstack-query-recommended)
- [Checklist](#checklist)
## Overview
Best practices for connecting storefront to ecommerce backend APIs. Framework-agnostic patterns for authentication, cart state management, error handling, and performance optimization.
**For Medusa-specific integration**, see `reference/medusa.md` for SDK setup, pricing, regions, and Medusa patterns.
## Detecting the Backend (CRITICAL)
**Before implementing any backend integration, identify which ecommerce backend is being used.**
### Detection Strategy
**1. Check for monorepo structure:**
```bash
# Look for backend directory
ls -la ../backend
ls -la ./backend
ls -la ../../apps/backend
```
Common monorepo patterns:
- `/apps/storefront` + `/apps/backend`
- `/frontend` + `/backend`
- `/packages/web` + `/packages/api`
**2. Check package.json dependencies:**
```json
{
"dependencies": {
"@medusajs/js-sdk": "...", // Medusa
// check other ecommerce frameworks...
}
}
```
**3. Check environment variables:**
```bash
# Look in .env, .env.local, .env.example
grep -i "api\|backend\|medusa\|shopify\|commerce" .env*
```
Common patterns:
- `NEXT_PUBLIC_MEDUSA_BACKEND_URL` → Medusa
- Custom `API_URL` or `BACKEND_URL` → Other backend
**4. If unsure, ASK THE USER:**
```markdown
I need to connect to the ecommerce backend. Which backend are you using?
Options:
- Medusa (open-source headless commerce)
- Custom backend
- Other
```
### Backend Documentation and MCP Servers
**ALWAYS refer to the backend's official documentation or MCP server for:**
- API endpoints and data structures
- Authentication requirements
- SDK usage and installation
- Environment configuration
- Rate limits and best practices
**For Medusa:**
- Documentation: https://docs.medusajs.com
- MCP Server: If available, use Medusa MCP server for real-time API information
- JS SDK docs: https://docs.medusajs.com/resources/js-sdk
- See `reference/medusa.md` for detailed integration guide
**For other backends:**
- Check the backend's documentation portal
- Look for MCP server if available
- Verify API endpoints and authentication methods
- Never assume API structure without verification
**Important:** Do not guess API endpoints or data formats. Always verify with documentation or ask the user to confirm the backend's API structure.
## Framework Detection
Identify the frontend framework to determine appropriate data fetching patterns:
**Next.js:**
- App Router: Server Components (async/await), Client Components (useEffect/TanStack Query)
- Pages Router: getServerSideProps/getStaticProps (server), useEffect (client)
**SvelteKit:**
- Load functions for server-side data
- Client-side: fetch in component lifecycle
**TanStack Start:**
- Server functions for server-side data
- Client-side: fetch with React hooks
**General Rule:**
- **Server-side for initial load**: SEO, performance, security (product pages, listings)
- **Client-side for interactions**: Cart, filters, search, user-specific data
## Environment Configuration
**Store API URLs and keys in environment variables:**
```typescript
// .env.local
NEXT_PUBLIC_API_URL=https://api.example.com
NEXT_PUBLIC_PUBLISHABLE_KEY=pk_...
```
**Framework-specific prefixes:**
- Next.js: `NEXT_PUBLIC_` for client-side
- SvelteKit: `PUBLIC_` for client-side
- Vite-based (TanStack Start): `VITE_` for client-side
**Security:**
- ❌ NEVER expose secret/admin keys in client-side code
- ✅ Publishable keys are safe for client (Medusa, Stripe)
- ✅ Secret keys only in server-side code or environment
## Backend-Specific Integration
### Medusa Backend
**For complete Medusa integration guide**, see `reference/medusa.md` which covers:
- SDK installation and setup
- Vite configuration (for TanStack Start, etc.)
- TypeScript types from `@medusajs/types`
- Price display (never divide by 100)
- Common operations (products, cart, categories, customers)
- Custom endpoints
- Region state management
- Error handling with SDK
### Other Backends
For non-Medusa backends (custom APIs, third-party platforms):
**1. Consult backend's API documentation** for:
- Authentication requirements
- Available endpoints
- Request/response formats
- SDK availability (check if official SDK exists)
**2. Use backend's official SDK if available** - provides type safety, error handling, and best practices
**3. If no SDK, create API client wrapper:**
- Centralize API calls in one module
- Group by resource (products, cart, customers, orders)
- Handle authentication (include tokens/cookies)
- Handle errors consistently
- Use native fetch or axios
## Authentication Patterns
### Customer Authentication
**Session-based (cookies):**
- Backend manages session via cookies
- No manual token management needed
- Works across page refreshes
- Common in traditional ecommerce backends
- Call backend login endpoint, check auth state, logout methods
**Token-based (JWT, OAuth):**
- Store token in localStorage or secure cookie after login
- Include token in Authorization header for all authenticated requests
- Common in headless/API-first backends
- Format: `Authorization: Bearer {token}`
### Protecting Customer Routes
**Check authentication before rendering customer-specific pages** (account, orders, addresses):
- **Server-side**: Check auth in server functions (getServerSideProps, load functions, etc.). Redirect to login if not authenticated.
- **Client-side**: Check auth state on mount. Redirect to login if not authenticated.
Use framework-specific auth patterns for redirects.
### Cart Access Pattern
**Guest carts:**
- Store cart ID in localStorage or cookie
- Check for existing cart ID on app load
- Create new cart if none exists
- Allows shopping without account
- Persists across sessions
**Logged-in carts:**
- Associate cart with customer account
- Syncs across devices
- **CRITICAL: Merge guest cart with customer cart on login** - Transfer guest cart items to customer's account cart, then clear guest cart ID from localStorage
## Cart State Management
**Critical ecommerce pattern**: Cart must be accessible throughout the app.
### Global Cart State
**React Context (for simple cases):**
- Create CartContext and CartProvider
- Store cart state and cartId (from localStorage)
- Load cart on mount if cartId exists
- Provide methods: addItem, removeItem, updateQuantity, clearCart
- Update cart state after each operation
**State management libraries (Zustand, Redux):**
- Use for complex state requirements
- Better for large applications
- Easier to debug with DevTools
- Same pattern: Store cart, provide actions, sync with backend
**Key requirements:**
- Cart accessible from any component
- Real-time cart count updates
- Optimistic UI updates (update UI immediately, sync with backend)
### Cart Cleanup After Order Placement (CRITICAL)
**IMPORTANT: After order is successfully placed, you MUST reset the cart state.**
**Common issue:** Cart popup and global cart state still show old items after order completion. This happens when cart state isn't cleared after checkout.
**Required cleanup actions:**
1. **Clear cart from global state** - Reset cart state to null/empty in Context/Zustand/Redux
2. **Clear localStorage cart ID** - Remove cart ID: `localStorage.removeItem('cart_id')`
3. **Invalidate cart queries** - If using TanStack Query: `queryClient.invalidateQueries({ queryKey: ['cart'] })`
4. **Update cart count to 0** - Navbar and UI should reflect empty cart
**When to clear:**
- After successful order placement (order confirmed)
- On navigation to order confirmation page
- Before redirecting to thank you page
**Why this is critical:**
- Prevents "phantom cart" from appearing in cart popup after order
- Ensures clean state for next shopping session
- Improves UX by not showing old cart items
## Error Handling for Ecommerce
### Ecommerce-Specific Errors
**Out of stock:**
- Catch errors when adding to cart
- Check for "out of stock" or "inventory" in error message
- Show user-friendly message: "Sorry, this item is now out of stock"
- Update product availability UI to show out of stock
**Price changed during checkout:**
- Compare cart total with expected total
- If different, show warning: "Prices have been updated. Please review your cart."
- Highlight changed prices in cart
**Payment failed:**
- Catch errors during order completion
- Check for specific payment errors: payment_declined, insufficient_funds, etc.
- Show specific messages:
- Payment declined → "Payment declined. Please try a different payment method."
- Insufficient funds → "Insufficient funds. Please use a different card."
- Generic → "Payment failed. Please try again or contact support."
**Session expired:**
- Catch 401/Unauthorized errors
- Clear auth state
- Redirect to login with message: "Your session has expired. Please log in again."
### User-Friendly Error Messages
**Transform technical errors to clear messages:**
- Network/fetch errors → "Unable to connect. Please check your internet connection."
- Timeout errors → "Request timed out. Please try again."
- Inventory errors → "This item is no longer available in the requested quantity."
- Generic fallback → "Something went wrong. Please try again or contact support."
**Pattern**: Check error message or status code, map to user-friendly message, show in UI (toast, banner, inline).
## Performance Patterns
### Data Fetching with TanStack Query (RECOMMENDED)
**Use TanStack Query for all backend API calls** - provides automatic caching, request deduplication, loading/error states, and optimistic updates.
**Installation:** `npm install @tanstack/react-query`
**Setup:**
- Create QueryClient with default options (staleTime: 5 min, retry: 1)
- Wrap app with QueryClientProvider
**Query pattern (for fetching data):**
- Use `useQuery` with queryKey and queryFn
- queryKey: Array with resource and identifier `['products', categoryId]`
- queryFn: API call function
- Returns: `data`, `isLoading`, `error`
- Use for: Products, cart, customer data, categories
**Mutation pattern (for modifying data):**
- Use `useMutation` with mutationFn
- mutationFn: API operation (add to cart, update, delete)
- onSuccess: Update cache or invalidate queries
- Returns: `mutate` function, `isPending` state
- Use for: Add to cart, remove from cart, update quantities, place order
**Benefits:**
- Automatic caching (no manual cache management)
- Built-in loading/error states
- Request deduplication
- Optimistic updates (update UI before server responds)
- Cache invalidation strategies
**Ecommerce-specific usage:**
- Products: Long stale time (5-10 min) - products don't change often
- Cart: Short or no stale time - prices/inventory can change
- Categories: Long stale time - rarely change
### Caching Strategy
**Client-side caching:**
- TanStack Query handles automatically with `staleTime` and `cacheTime`
- Configure globally or per-query
- Product data: 5-10 min stale time
- Cart data: Fresh on every fetch
- Categories: Long stale time
**Server-side caching (framework-specific):**
- Next.js: Use `revalidate` export or cache configuration
- Set revalidation period (e.g., 300 seconds for product pages)
- Static generation with ISR for product pages
### Request Deduplication
TanStack Query and modern frameworks handle this automatically - multiple components requesting same data result in single request.
### Pagination Pattern
**Offset-based:** Pass limit and offset parameters to API `limit: 24, offset: page * 24`
**Cursor-based (better performance):** Pass limit and cursor (last item ID) `limit: 24, cursor: lastProductId`
Check backend documentation for supported pagination type.
## Checklist
**Essential backend integration:**
- [ ] Backend detected (Medusa, Shopify, custom, etc.)
- [ ] Environment variables configured (API URL, keys)
- [ ] Framework-specific data fetching patterns identified
- [ ] **RECOMMENDED: TanStack Query installed and configured for API calls**
- [ ] Server-side fetching for product pages (SEO)
- [ ] Client-side fetching for cart and user interactions (use TanStack Query)
- [ ] Authentication flow implemented (login/logout)
- [ ] Cart ID persisted in localStorage or cookies
- [ ] Global cart state management (context or store)
- [ ] Cart count synced across app
- [ ] Optimistic UI updates for cart operations
- [ ] Error handling for out of stock scenarios
- [ ] Error handling for payment failures
- [ ] Session expiration handling (redirect to login)
- [ ] User-friendly error messages (not technical)
- [ ] Caching strategy for product data
- [ ] Stock availability checks before checkout
- [ ] Price change detection and warnings
**For Medusa backends, also check:**
- [ ] Medusa SDK installed (`@medusajs/js-sdk` + `@medusajs/types`)
- [ ] SDK initialized with baseUrl and publishableKey
- [ ] Vite SSR config added (if using TanStack Start/Vite)
- [ ] Using official types from `@medusajs/types`
- [ ] Not dividing prices by 100 (display as-is)
- [ ] Region context implemented for multi-region stores
- [ ] Region passed to cart and product queries
See `reference/medusa.md` for complete Medusa integration guide.