API Integration

The Inventory Management UI is designed to work seamlessly with the Inventory Management API. This page documents how the frontend application integrates with the backend services.

🔗 API Overview

The application communicates with a RESTful API that provides the following resources:

Core Resources

Resource Description Endpoints
Items Inventory objects and monuments GET /item, POST /item, PUT /item/{id}, DELETE /item/{id}
Partners Museums, institutions, and individuals GET /partner, POST /partner, PUT /partner/{id}, DELETE /partner/{id}
Projects Collections with launch dates and status GET /project, POST /project, PUT /project/{id}, DELETE /project/{id}
Tags Categorization system for items GET /tag, POST /tag, PUT /tag/{id}, DELETE /tag/{id}
Pictures Image management with upload capabilities GET /picture, POST /picture, PUT /picture/{id}, DELETE /picture/{id}

Reference Data

Resource Description Usage
Countries Country reference data Used in partner and item forms
Languages Language reference data Used in project configuration
Contexts Content organization contexts Used in project and item organization

🔐 Authentication

The application uses JWT Bearer Token authentication:

Login Flow

// 1. User submits credentials
const loginData = {
  email: 'user@example.com',
  password: 'password123'
}

// 2. API returns JWT token
const response = await apiClient.login(loginData)
const token = response.data.access_token

// 3. Token stored in localStorage
localStorage.setItem('token', token)

// 4. Token automatically included in subsequent requests
// via Axios interceptors

Token Management

🏗️ API Client Architecture

The application uses a centralized API client (src/api/client.ts) that provides:

Type-Safe Interface

export interface ItemResource {
  id: string
  internal_name: string
  backward_compatibility: string | null
  type: 'object' | 'monument'
  partner?: PartnerResource
  project?: ProjectResource
  country?: CountryResource
  tags?: TagResource[]
  created_at: string | null
  updated_at: string | null
}

Standardized Methods

class APIClient {
  // CRUD operations for each resource
  async getItems(): Promise<ApiResponse<ItemResource[]>>
  async getItem(id: string): Promise<ApiResponse<ItemResource>>
  async createItem(data: Partial<ItemResource>): Promise<ApiResponse<ItemResource>>
  async updateItem(id: string, data: Partial<ItemResource>): Promise<ApiResponse<ItemResource>>
  async deleteItem(id: string): Promise<void>
  
  // Tag management for items
  async getItemTags(itemId: string): Promise<ApiResponse<TagResource[]>>
  async addTagToItem(itemId: string, tagId: string): Promise<void>
  async removeTagFromItem(itemId: string, tagId: string): Promise<void>
}

Error Handling

try {
  const response = await apiClient.getItems()
  items.value = response.data
} catch (error: any) {
  if (error.response?.status === 401) {
    // Redirect to login
    router.push('/login')
  } else {
    // Show user-friendly error message
    errorMessage.value = error.response?.data?.message || 'An error occurred'
  }
}

📡 Request/Response Patterns

Standard API Response Format

interface ApiResponse<T> {
  data: T
  message?: string
  status: 'success' | 'error'
}

Request Examples

Creating an Item

// Frontend request
const newItem = {
  internal_name: 'Ancient Vase',
  type: 'object' as const,
  partner_id: 'partner-uuid',
  project_id: 'project-uuid'
}

const response = await apiClient.createItem(newItem)

Updating with Relationships

// Update item with new partner
const updatedItem = {
  internal_name: 'Updated Name',
  partner_id: 'new-partner-uuid'
}

const response = await apiClient.updateItem(itemId, updatedItem)

Tag Management

// Add tag to item
await apiClient.addTagToItem(itemId, tagId)

// Remove tag from item
await apiClient.removeTagFromItem(itemId, tagId)

// Get all tags for item
const tags = await apiClient.getItemTags(itemId)

🔄 State Management Integration

The API client integrates with Pinia stores for state management:

Auth Store

export const useAuthStore = defineStore('auth', () => {
  const token = ref<string | null>(localStorage.getItem('token'))
  const user = ref<User | null>(null)
  
  const login = async (credentials: LoginCredentials) => {
    const response = await apiClient.login(credentials)
    token.value = response.data.access_token
    localStorage.setItem('token', token.value)
  }
  
  const logout = () => {
    token.value = null
    user.value = null
    localStorage.removeItem('token')
    router.push('/login')
  }
  
  return { token, user, login, logout, isAuthenticated }
})

🌐 Environment Configuration

API integration is configured through environment variables:

# .env.example
VITE_API_BASE_URL=http://localhost:8000/api
VITE_APP_TITLE=Inventory Management UI

Environment-Specific Configurations

🚦 Loading States & Error Handling

Loading States

<template>
  <div v-if="loading" class="text-center py-8">
    <div class="animate-spin rounded-full h-12 w-12 border-b-2 border-primary-600 mx-auto"></div>
  </div>
  
  <div v-else-if="error" class="text-red-600 text-center py-8">
    
  </div>
  
  <div v-else>
    <!-- Content -->
  </div>
</template>

Error Handling Patterns

const fetchData = async () => {
  loading.value = true
  error.value = null
  
  try {
    const response = await apiClient.getData()
    data.value = response.data
  } catch (err: any) {
    error.value = err.response?.data?.message || 'Failed to load data'
  } finally {
    loading.value = false
  }
}

🔍 Development & Testing

API Mocking

For testing, API calls are mocked using Vitest:

// Test setup
vi.mock('@/api/client', () => ({
  apiClient: {
    getItems: vi.fn(),
    createItem: vi.fn(),
    updateItem: vi.fn(),
    deleteItem: vi.fn()
  }
}))

// Test usage
const mockApiClient = apiClient as any
mockApiClient.getItems.mockResolvedValue({
  data: [mockItem1, mockItem2]
})

Local Development

For local development without the API:

  1. Mock API Server: Use tools like JSON Server or MSW
  2. Proxy Configuration: Configure Vite proxy to backend
  3. Environment Variables: Point to local API instance

API Specification Management

Fetching the API Specification

To fetch the latest API specification from the Inventory API, run:

npm run inventory-app:fetch

This will download the specification and store it in src/api/inventory-app.json.

Comparing API Specification Changes

To compare the local API specification with the latest version online, run:

npm run inventory-app:diff

This will display the differences between the local and remote versions.


For more detailed API documentation, see the Backend API Repository.

Last updated: July 10, 2025

Local Development: This is a basic layout for local Jekyll development. When deployed to GitHub Pages, this site will use the just-the-docs theme.