Skip to content

Frontend API Adapter Documentation

This document describes the modifications made to the frontend API service to work with the new Medusa v2 backend.

Overview

The frontend API service (frontend/store/src/services/api.js) has been updated to communicate with the Medusa v2 backend instead of the previous Supabase-based backend. The changes include:

  1. Updated API base URL
  2. Updated endpoint paths for custom modules
  3. Updated response data extraction for new API formats
  4. Added new store API functions for custom modules

Changes Made

1. API Base URL

Before:

const API_BASE_URL = import.meta.env.VITE_API_BASE_URL || (isLocalhost ? 'http://localhost:8000/api' : 'https://api.azhar.store/api');

After:

const API_BASE_URL = import.meta.env.VITE_API_BASE_URL || (isLocalhost ? 'http://localhost:9000/store' : 'https://api.azhar.store/store');

Rationale: Medusa v2 serves the store API at /store prefix on port 9000 by default.

2. Store API Endpoints for Custom Modules

Added new store API functions for the custom modules:

// Store API endpoints for custom modules
export const getTranslations = () => api.get('/translations').then(res => res.data);
export const getSettings = () => api.get('/settings').then(res => res.data);
export const getAdvertisements = () => api.get('/advertisements').then(res => res.data.advertisements);

Response Formats:

  • Translations: Returns i18next-compatible bundle directly

    {
      "ar": {
        "common": {
          "welcome": "مرحبا"
        }
      }
    }
    

  • Settings: Returns typed settings object

    {
      "free_delivery_threshold": 1000,
      "pickup_message": "Your order will be ready in 30 minutes",
      "ceo_whatsapp": "+97312345678"
    }
    

  • Advertisements: Returns object with advertisements array

    {
      "advertisements": [
        {
          "id": "adv_001",
          "title": "Summer Sale",
          "image_url": "https://...",
          "link_url": "https://...",
          "location": "home_slider",
          "display_order": 0,
          "is_active": true
        }
      ]
    }
    

3. Admin API Endpoints for Custom Modules

Updated admin API functions to use the correct request format:

// Admin API endpoints for custom modules (require admin authentication)
export const updateTranslation = ({ id, value }) => api.patch(`/admin/translations/${id}`, { value });
export const createTranslation = (data) => api.post('/admin/translations', data);
export const updateAppSettings = (data) => api.patch('/admin/settings', { settings: data });

Request Formats:

  • Update Settings: Requires settings wrapped in object
    {
      "settings": {
        "free_delivery_threshold": 1000,
        "pickup_message": "Updated message"
      }
    }
    

4. Order Creation

Updated order creation to extract the order from the response:

createOrder: (data) => api.post('/orders', data).then(res => res.data.order),

Response Format:

{
  "order": {
    "id": "order_001",
    "status": "pending",
    "total": 1500,
    "items": [...]
  }
}

5. Updated apiService Methods

Updated the duplicate methods in apiService object to match the new API:

getAppSettings: () => api.get('/settings').then(res => res.data),
updateAppSettings: (data) => api.patch('/admin/settings', { settings: data }),
getTranslations: () => api.get('/translations').then(res => res.data),
getAdvertisements: () => api.get('/advertisements').then(res => res.data.advertisements),

API Endpoints Reference

Store Endpoints (Public)

Endpoint Method Description Response
/store/translations GET Get all translations as i18next bundle Translation bundle
/store/settings GET Get application settings Settings object
/store/advertisements GET Get active advertisements { advertisements: [...] }
/store/orders POST Create order via workflow { order: {...} }

Admin Endpoints (Authenticated)

Endpoint Method Description Request Body
/admin/translations GET List all translations -
/admin/translations POST Create translation { language_code, key, value, section }
/admin/translations/:id PATCH Update translation { language_code, key, value, section }
/admin/translations/:id DELETE Delete translation -
/admin/settings GET Get all settings -
/admin/settings PATCH Bulk update settings { settings: {...} }
/admin/advertisements GET List all advertisements -
/admin/advertisements POST Create advertisement { title, image_url, link_url, location, display_order, is_active }
/admin/advertisements/:id PATCH Update advertisement { title, image_url, link_url, location, display_order, is_active }
/admin/advertisements/:id DELETE Delete advertisement -

Authentication

The API adapter uses JWT token authentication via the Authorization header:

api.interceptors.request.use(
  (config) => {
    const token = localStorage.getItem('token');
    if (token) {
      config.headers.Authorization = `Bearer ${token}`;
    }
    return config;
  },
  (error) => Promise.reject(error)
);

Note: For admin endpoints, Medusa uses cookie-based authentication by default. The frontend may need to be updated to use cookie authentication for admin operations, or the backend may need to be configured to accept JWT tokens for admin endpoints.

Error Handling

The API adapter includes automatic 401 handling:

api.interceptors.response.use(
  (response) => response,
  (error) => {
    if (error.response?.status === 401) {
      localStorage.removeItem('token');
      window.location.href = '/login';
    }
    return Promise.reject(error);
  }
);

Environment Variables

The API base URL can be overridden using the VITE_API_BASE_URL environment variable:

# .env file
VITE_API_BASE_URL=http://localhost:9000/store

Or for production:

VITE_API_BASE_URL=https://api.azhar.store/store

Usage Examples

Fetching Translations

import { getTranslations } from './services/api';

const translations = await getTranslations();
// Returns: { ar: { common: { welcome: "مرحبا" } } }

Fetching Settings

import { getSettings } from './services/api';

const settings = await getSettings();
// Returns: { free_delivery_threshold: 1000, pickup_message: "...", ceo_whatsapp: "..." }

Fetching Advertisements

import { getAdvertisements } from './services/api';

const ads = await getAdvertisements();
// Returns: [{ id: "adv_001", title: "Summer Sale", image_url: "...", ... }]

Creating an Order

import { apiService } from './services/api';

const order = await apiService.createOrder({
  items: [
    { product_id: "prod_001", quantity: 2 }
  ],
  shipping_address: {
    first_name: "John",
    last_name: "Doe",
    address_1: "123 Main St",
    city: "Manama",
    country_code: "BH"
  },
  shipping_method: "standard"
});
// Returns: { id: "order_001", status: "pending", ... }

Updating Settings (Admin)

import { updateAppSettings } from './services/api';

await updateAppSettings({
  free_delivery_threshold: 1500,
  pickup_message: "Updated message"
});

Migration Notes

Breaking Changes

  1. Base URL Changed: From localhost:8000/api to localhost:9000/store
  2. Response Format Changes: Some endpoints now return wrapped responses (e.g., { advertisements: [...] } instead of direct array)
  3. Settings Update Format: Settings updates now require { settings: {...} } wrapper

Compatibility

The following endpoints remain unchanged and should work without modification:

  • Products endpoints (if using Medusa's product module)
  • Categories endpoints (if using Medusa's product category module)
  • Customers endpoints (if using Medusa's customer module)

Testing Checklist

After updating the frontend, verify:

  • [ ] Store loads without errors
  • [ ] Advertisements display on homepage
  • [ ] Settings are applied (delivery threshold, pickup message)
  • [ ] Translations load correctly
  • [ ] Order creation works
  • [ ] Admin pages load (if using admin UI)
  • [ ] Admin CRUD operations work for custom modules

Troubleshooting

404 Errors on API Calls

Problem: API calls return 404 Not Found

Solution: 1. Verify the backend is running on port 9000 2. Check the API base URL in environment variables 3. Verify the endpoint path matches the Medusa route

CORS Errors

Problem: Browser shows CORS errors

Solution: 1. Verify CORS is configured in medusa-config.ts 2. Ensure the store URL is in the CORS allowed origins 3. Check that the backend is running with CORS enabled

Authentication Errors

Problem: 401 Unauthorized on admin endpoints

Solution: 1. Verify admin is logged in 2. Check that authentication cookies are being sent 3. Consider updating to use cookie-based authentication for admin endpoints

Response Format Mismatches

Problem: Frontend code expects different response format

Solution: 1. Check the actual response format in browser dev tools 2. Update the API service to extract the correct data 3. Refer to the API documentation for expected formats

Future Enhancements

Potential improvements to the API adapter:

  1. TypeScript Migration: Convert to TypeScript for better type safety
  2. API Client Generation: Generate API client from OpenAPI/Swagger spec
  3. Retry Logic: Add automatic retry for failed requests
  4. Request Caching: Add caching for GET requests
  5. Request Cancelation: Add ability to cancel pending requests
  6. Error Boundaries: Add better error handling and user feedback
  7. Loading States: Add built-in loading state management