Skip to content
Last update: June 24, 2025

How-To: Using API Clients with useApiClient

The useApiClient composable provides a standardized way to access authenticated API clients in VC-Shell applications. This guide demonstrates how to effectively use API clients for data fetching, CRUD operations, and integration with other composables.

Prerequisites

  • Understanding of Vue 3 Composition API, including async/await and reactive state.
  • Familiarity with the useApiClient composable (see useApiClient API Reference).
  • Basic knowledge of TypeScript interfaces and API client classes.
  • Understanding of VC-Shell's composable patterns and data management.

Core Concept

useApiClient creates authenticated API client instances that handle:

  • Authentication: Automatic token management for API requests
  • Base URL Configuration: Proper endpoint resolution
  • Type Safety: Full TypeScript support for API operations
  • Consistent Interface: Standardized way to access different API services

The composable takes an API client class and returns a factory function that provides authenticated instances.

import { useApiClient } from '@vc-shell/framework';
import { VcmpSellerCatalogClient } from '@your-api-package';

const { getApiClient } = useApiClient(VcmpSellerCatalogClient);

// Get authenticated client instance
const client = await getApiClient();
const result = await client.searchProducts(query);

Implementation Patterns

1. Basic API Client Setup

The most common pattern is to set up API clients at the module level:

// Module-level API client setup
import { useApiClient } from '@vc-shell/framework';
import { 
  VcmpSellerCatalogClient,
  VcmpPublicationRequestClient,
  StateMachineClient 
} from '@your-api-package';

// Create API client factories
const { getApiClient } = useApiClient(VcmpSellerCatalogClient);
const { getApiClient: getRequestApiClient } = useApiClient(VcmpPublicationRequestClient);
const { getApiClient: getStateMachineApiClient } = useApiClient(StateMachineClient);

2. API Client in Data Loading

Use API clients for loading and fetching data in composables:

// Loading data with API client
async function loadProductDetails(productId: string) {
  const client = await getApiClient();
  const product = await client.getProductById(productId);
  return product;
}

// Search with query parameters
async function searchProducts(query: ISearchProductsQuery) {
  const client = await getApiClient();
  const searchQuery = new SearchProductsQuery(query);
  return await client.searchProducts(searchQuery);
}

3. CRUD Operations Pattern

Implement create, read, update, delete operations using API clients:

// CRUD operations with API clients
const productOperations = {
  // Create
  async create(productData: ProductDetails) {
    const client = await getApiClient();
    const command = new CreateNewProductCommand({
      sellerId: await getSellerId(),
      productDetails: productData
    });
    return await client.createNewProduct(command);
  },

  // Read
  async getById(id: string) {
    const client = await getApiClient();
    return await client.getProductById(id);
  },

  // Update
  async update(product: IProductDetails) {
    const client = await getApiClient();
    const command = new UpdateProductDetailsCommand({
      sellerId: await getSellerId(),
      sellerProductId: product.id,
      productDetails: new ProductDetails(product)
    });
    return await client.updateProductDetails(command);
  },

  // Delete
  async remove(productIds: string[]) {
    const client = await getApiClient();
    return await client.deleteProducts(productIds);
  }
};

4. Multiple API Clients in One Composable

Use multiple API clients when working with different services:

// Multiple API clients for different operations
export function useProductManagement() {
  const { getApiClient } = useApiClient(VcmpSellerCatalogClient);
  const { getApiClient: getRequestApiClient } = useApiClient(VcmpPublicationRequestClient);
  const { getApiClient: getStateMachineApiClient } = useApiClient(StateMachineClient);

  async function saveAndSubmitForApproval(product: IProductDetails) {
    // Save product using catalog client
    const catalogClient = await getApiClient();
    const savedProduct = await catalogClient.updateProductDetails(command);

    // Submit for approval using request client
    const requestClient = await getRequestApiClient();
    const requestCommand = new CreateSmPublicationRequestCommand({
      sellerId: await getSellerId(),
      productId: savedProduct.id
    });
    await requestClient.createNewPublicationRequest(requestCommand);

    return savedProduct;
  }
}

5. API Client with Search and Pagination

Handle search operations with pagination using API clients:

// Search with pagination
export function useProductSearch() {
  const { getApiClient } = useApiClient(VcmpSellerCatalogClient);

  async function searchWithPagination(searchParams: {
    keyword?: string;
    skip?: number;
    take?: number;
    sort?: string;
  }) {
    const client = await getApiClient();
    const query = new SearchProductsQuery({
      sellerId: await getSellerId(),
      ...searchParams
    });

    return await client.searchProducts(query);
  }

  async function searchCategories(keyword?: string, skip = 0, ids?: string[]) {
    const client = await getApiClient();
    return await client.searchCategories(
      new SearchCategoriesQuery({
        sellerId: await getSellerId(),
        objectIds: ids,
        keyword,
        skip,
        take: 20
      })
    );
  }
}

6. API Client with Validation

Use API clients for data validation operations:

// Validation using API client
export function useProductValidation() {
  const { getApiClient } = useApiClient(VcmpSellerCatalogClient);

  async function validateProduct(product: ISellerProduct) {
    const client = await getApiClient();
    const query = new ValidateProductQuery({
      sellerProduct: new SellerProduct(product)
    });

    try {
      return await client.validateProduct(query);
    } catch (error) {
      console.error('Validation failed:', error);
      throw error;
    }
  }

  async function validateGtin(gtin: string, productId?: string) {
    const product = { gtin, id: productId } as ISellerProduct;
    const errors = await validateProduct(product);
    return errors.filter(error => 
      error.propertyName?.toLowerCase() === 'gtin'
    );
  }
}

Integration with Other Composables

With useAsync

Combine useApiClient with useAsync for loading state management:

import { useAsync, useApiClient } from '@vc-shell/framework';

export function useProductLoader() {
  const { getApiClient } = useApiClient(VcmpSellerCatalogClient);

  const { action: loadProduct, loading } = useAsync(async (productId: string) => {
    const client = await getApiClient();
    return await client.getProductById(productId);
  });

  return {
    loadProduct,
    loading
  };
}

Error Handling

Always implement proper error handling when using API clients:

// Error handling pattern
export function useProductOperations() {
  const { getApiClient } = useApiClient(VcmpSellerCatalogClient);

  async function safeApiCall<T>(operation: () => Promise<T>): Promise<T | null> {
    try {
      return await operation();
    } catch (error) {
      console.error('API operation failed:', error);

      // Handle specific error types
      if (error.status === 404) {
        console.warn('Resource not found');
      } else if (error.status === 403) {
        console.warn('Access denied');
      }

      throw error; // Re-throw for caller to handle
    }
  }

  async function loadProductSafely(id: string) {
    return safeApiCall(async () => {
      const client = await getApiClient();
      return await client.getProductById(id);
    });
  }
}

Best Practices

  • Consistent Naming: Use descriptive names for API client factories.

  • Error Handling: Always wrap API calls in try-catch blocks and provide meaningful error messages.

  • Type Safety: Use proper TypeScript interfaces and command classes for API operations.

  • Reusability: Create reusable functions for common API operations within your composables.

  • Authentication: Let useApiClient handle authentication automatically - don't manually manage tokens.

  • Resource Cleanup: API clients are automatically managed, no manual cleanup required.

By following these patterns and best practices, you can effectively use useApiClient to build robust and maintainable API integrations in your VC-Shell applications.