API Reference

Table of Contents

  1. Overview

  2. Authentication

  3. User Worker API

  4. Image Worker API

  5. PDF Worker API

  6. Data Worker API

  7. Keys Worker API

  8. Turnstile Worker API

  9. Error Handling

  10. Type Definitions

  11. SDK Examples

Overview

Striae's backend consists of six Cloudflare Workers that provide specialized API services. All APIs use RESTful conventions and return JSON responses.

Authentication

Authentication Methods

All worker APIs use custom authentication headers:

X-Custom-Auth-Key: {api_key}

API keys are generated by the Keys Worker and should be obtained through the authentication flow.

Note: The Image Worker uses a different authentication method with Authorization: Bearer {token} header.

Authentication Environment Variables:

  • User Worker: Uses USER_DB_AUTH, SL_API_KEY, R2_KEY_SECRET, and IMAGES_API_TOKEN environment variables

  • Data Worker: Uses R2_KEY_SECRET environment variable

  • Keys Worker: Uses KEYS_AUTH environment variable

  • Image Worker: Uses API_TOKEN environment variable

  • PDF Worker: No authentication required

  • Turnstile Worker: No authentication required

CORS Policy

All workers implement strict CORS policies:

  • Allowed Origin: https://www.striae.org

  • Allowed Methods: Varies by worker

  • Allowed Headers: Content-Type, X-Custom-Auth-Key, Authorization

User Worker API

Base URL: {USER_WORKER_URL}

Authentication: X-Custom-Auth-Key header

Environment Variables Required:

  • USER_DB_AUTH - KV database authentication

  • SL_API_KEY - SendLayer email service for deletion confirmations

  • R2_KEY_SECRET - Data worker API authentication for case deletion

  • IMAGES_API_TOKEN - Image worker API authentication for file deletion

Endpoints

Get User Data

GET /{userUid}

Description: Retrieve user profile data from KV storage

Parameters:

  • userUid (path): Firebase user UID

Response:

{
  "uid": "string",
  "email": "string",
  "firstName": "string",
  "lastName": "string",
  "company": "string",
  "permitted": boolean,
  "cases": [
    {
      "caseNumber": "string",
      "createdAt": "ISO 8601 date"
    }
  ],
  "createdAt": "ISO 8601 date",
  "updatedAt": "ISO 8601 date"
}

Status Codes:

  • 200: Success

  • 404: User not found

  • 401: Unauthorized (invalid auth header)

  • 500: Server error

Create/Update User

PUT /{userUid}

Description: Create new user or update existing user data. Preserves existing cases when updating.

Parameters:

  • userUid (path): Firebase user UID

Request Body:

{
  "email": "string",
  "firstName": "string", 
  "lastName": "string",
  "company": "string",
  "permitted": boolean
}

Response: User object (same as GET response)

Status Codes:

  • 200: User updated

  • 201: User created

  • 401: Unauthorized

  • 500: Server error

Delete User

DELETE /{userUid}

Description: Delete user and all associated data including cases, files, and images. Sends confirmation emails to user and admin.

Parameters:

  • userUid (path): Firebase user UID

Process:

  1. Retrieves user data for email confirmation

  2. Deletes all user's cases and associated files from data worker

  3. Deletes all associated images from image worker

  4. Sends deletion confirmation email to user via SendLayer

  5. Sends admin notification email

  6. Deletes user account from KV storage

Security Notes:

  • Demo accounts (permitted: false) should be protected from deletion at the UI level

  • Deletion includes all user data, cases, files, and annotations

  • Action is irreversible and permanent

  • Sends email confirmations using SendLayer service

Response:

{
  "success": true,
  "message": "Account successfully deleted and confirmation emails sent"
}

Error Response:

{
  "success": false,
  "message": "Account deletion failed: Unable to send confirmation emails"
}

Status Codes:

  • 200: Success

  • 404: User not found

  • 401: Unauthorized

  • 500: Server error (including email sending failures)

Add Cases to User

PUT /{userUid}/cases

Description: Add case assignments to user. Filters out duplicate case numbers.

Parameters:

  • userUid (path): Firebase user UID

Request Body:

{
  "cases": [
    {
      "caseNumber": "string"
    }
  ]
}

Response: Updated user object

Status Codes:

  • 200: Success

  • 404: User not found

  • 401: Unauthorized

  • 500: Server error

Remove Cases from User

DELETE /{userUid}/cases

Description: Remove case assignments from user. Does not delete the actual case data.

Parameters:

  • userUid (path): Firebase user UID

Request Body:

{
  "casesToDelete": ["caseNumber1", "caseNumber2"]
}

Response: Updated user object

Status Codes:

  • 200: Success

  • 404: User not found

  • 401: Unauthorized

  • 500: Server error

Image Worker API

Base URL: {IMAGE_WORKER_URL}

Authentication: Authorization: Bearer {API_TOKEN} header

Endpoints

Upload Image

POST /

Description: Upload image to Cloudflare Images

Request: Multipart form data with image file

Response:

{
  "result": {
    "id": "string",
    "filename": "string",
    "uploaded": "ISO 8601 date",
    "requireSignedURLs": true,
    "variants": ["string"]
  },
  "success": boolean,
  "errors": [],
  "messages": []
}

Status Codes:

  • 200: Success

  • 403: Forbidden (invalid token)

  • 400: Invalid file or missing file

  • 500: Server error

Get Signed URL

GET /{imageDeliveryPath}

Description: Generate signed URL for image access from imagedelivery.net URL

Parameters:

Response: Signed URL as plain text

Status Codes:

  • 200: Success

  • 403: Forbidden (invalid token)

  • 500: Server error

Delete Image

DELETE /{imageId}

Description: Delete image from Cloudflare Images

Parameters:

  • imageId (path): Cloudflare Images ID

Response:

{
  "success": boolean,
  "result": {},
  "errors": [],
  "messages": []
}

Status Codes:

  • 200: Success

  • 403: Forbidden (invalid token)

  • 404: Image not found

  • 500: Server error

PDF Worker API

Base URL: {PDF_WORKER_URL}

Authentication: None required

Endpoints

Generate PDF

POST /

Description: Generate PDF report with annotations

Request Body:

{
  "imageUrl": "string",
  "caseNumber": "string",
  "annotationData": {
    "leftCase": "string",
    "rightCase": "string",
    "leftItem": "string",
    "rightItem": "string",
    "caseFontColor": "string",
    "classType": "Bullet | Cartridge Case | Other",
    "customClass": "string",
    "classNote": "string",
    "indexType": "number | color",
    "indexNumber": "string",
    "indexColor": "string",
    "supportLevel": "ID | Exclusion | Inconclusive",
    "hasSubclass": boolean,
    "includeConfirmation": boolean,
    "additionalNotes": "string",
    "boxAnnotations": [
      {
        "id": "string",
        "x": "number (percentage 0-100)",
        "y": "number (percentage 0-100)", 
        "width": "number (percentage 0-100)",
        "height": "number (percentage 0-100)",
        "color": "string (hex color)"
      }
    ]
  },
  "activeAnnotations": ["string"],
  "currentDate": "string",
  "notesUpdatedFormatted": "string"
}

Response: PDF file (binary data)

Headers:

  • Content-Type: application/pdf

Status Codes:

  • 200: Success

  • 405: Method not allowed

  • 500: Server error

Data Worker API

Base URL: {DATA_WORKER_URL}

Authentication: X-Custom-Auth-Key header

Endpoints

Get File Data

GET /{filename}.json

Description: Retrieve JSON file data from R2 storage

Parameters:

  • filename (path): JSON filename (without .json extension in URL)

Response: JSON data from file or empty array if file doesn't exist

Status Codes:

  • 200: Success

  • 403: Forbidden

  • 500: Server error

Save File Data

PUT /{filename}.json

Description: Save JSON data to R2 storage file

Parameters:

  • filename (path): JSON filename (without .json extension in URL)

Request Body: Any valid JSON data

Response:

{
  "success": true
}

Status Codes:

  • 200: Success

  • 400: Invalid file type (non-JSON)

  • 403: Forbidden

  • 500: Server error

Delete File

DELETE /{filename}.json

Description: Delete JSON file from R2 storage

Parameters:

  • filename (path): JSON filename (without .json extension in URL)

Response:

{
  "success": true
}

Status Codes:

  • 200: Success

  • 404: File not found

  • 403: Forbidden

  • 500: Server error

Store Audit Entry

POST /audit/

Description: Create a new audit trail entry for compliance tracking

Query Parameters:

  • userId (required): User identifier

Request Body:

{
  "timestamp": "2025-09-23T14:30:15.123Z",
  "userId": "string",
  "userEmail": "string",
  "action": "AuditAction",
  "result": "AuditResult", 
  "details": {
    "fileName": "string",
    "fileType": "AuditFileType",
    "caseNumber": "string",
    "hashValid": "boolean",
    "validationErrors": ["string"],
    "workflowPhase": "WorkflowPhase",
    "performanceMetrics": {
      "processingTimeMs": "number",
      "fileSizeBytes": "number"
    },
    "fileDetails": {
      "fileId": "string",
      "originalFileName": "string",
      "fileSize": "number",
      "mimeType": "string",
      "uploadMethod": "string"
    },
    "annotationDetails": {
      "annotationType": "string",
      "tool": "string",
      "canvasPosition": {"x": "number", "y": "number"}
    }
  }
}

Response:

{
  "success": true,
  "entryCount": 15,
  "filename": "audit-trails/aDzwq3G6IBVRJVCEFijdg7B0fwq2-2025-09-23.json"
}

Status Codes:

  • 200: Audit entry stored successfully

  • 400: userId parameter required or invalid request data

  • 403: Forbidden

  • 500: Server error

Get User Audit Entries

GET /audit/

Description: Retrieve audit trail entries for a specific user

Query Parameters:

  • userId (required): User identifier

  • startDate (optional): Start date filter (YYYY-MM-DD format)

  • endDate (optional): End date filter (YYYY-MM-DD format)

Example:

GET /audit/?userId=aDzwq3G6IBVRJVCEFijdg7B0fwq2&startDate=2025-09-01&endDate=2025-09-30

Response:

{
  "entries": [
    {
      "timestamp": "2025-09-23T14:30:15.123Z",
      "userId": "aDzwq3G6IBVRJVCEFijdg7B0fwq2",
      "userEmail": "user@example.com",
      "action": "export",
      "result": "success",
      "details": {
        "fileName": "CASE-2025-001-annotations.json",
        "fileType": "json-data",
        "caseNumber": "CASE-2025-001",
        "hashValid": true,
        "validationErrors": [],
        "workflowPhase": "case-export"
      }
    }
  ],
  "total": 15
}

Status Codes:

  • 200: Success

  • 400: userId parameter required

  • 403: Forbidden

  • 500: Server error

Note: If no date range is specified, returns entries for the current date only. Date range queries read multiple daily files and aggregate results.

Keys Worker API

Base URL: {KEYS_WORKER_URL}

Authentication: X-Custom-Auth-Key header

Endpoints

Get Environment Key

GET /{keyName}

Description: Retrieve environment variable value

Parameters:

  • keyName (path): Environment variable name

Response: Plain text value of the environment variable

Status Codes:

  • 200: Success

  • 400: Key name required

  • 404: Key not found

  • 403: Forbidden

  • 500: Server error

Turnstile Worker API

Base URL: {TURNSTILE_WORKER_URL}

Authentication: None required

Endpoints

Verify CAPTCHA

POST /

Description: Verify Cloudflare Turnstile token

Request Body:

{
  "cf-turnstile-response": "string"
}

Response:

{
  "success": boolean,
  "error-codes": ["string"],
  "challenge_ts": "ISO 8601 date",
  "hostname": "string"
}

Status Codes:

  • 200: Verification completed (check success field)

  • 400: Invalid request or token missing

  • 405: Method not allowed

  • 500: Server error

Error Handling

Standard Error Response Format

{
  "error": "string",
  "code": "string",
  "message": "string",
  "details": {}
}

Common Error Codes

  • UNAUTHORIZED: Invalid or missing authentication

  • FORBIDDEN: Insufficient permissions

  • NOT_FOUND: Resource not found

  • VALIDATION_ERROR: Invalid request data

  • SERVER_ERROR: Internal server error

HTTP Status Codes

  • 200: Success

  • 201: Created

  • 400: Bad Request

  • 401: Unauthorized

  • 403: Forbidden

  • 404: Not Found

  • 405: Method Not Allowed

  • 500: Internal Server Error

Type Definitions

Audit Trail Types

ValidationAuditEntry Interface

Core audit entry structure for all validation events:

interface ValidationAuditEntry {
  timestamp: string;           // ISO 8601 timestamp
  userId: string;             // User identifier  
  userEmail: string;          // User email for identification
  action: AuditAction;        // What action was performed
  result: AuditResult;        // Success/failure/warning/blocked
  details: AuditDetails;      // Action-specific details
}

AuditAction Type

All supported audit actions:

type AuditAction = 
  // Case Management Actions
  | 'case-create' | 'case-rename' | 'case-delete'
  // Confirmation Workflow Actions  
  | 'case-export' | 'case-import' | 'confirmation-create' 
  | 'confirmation-export' | 'confirmation-import'
  // File Operations
  | 'file-upload' | 'file-delete' | 'file-access'
  // Annotation Operations
  | 'annotation-create' | 'annotation-edit' | 'annotation-delete'
  // User & Session Management
  | 'user-login' | 'user-logout' | 'user-profile-update' 
  | 'user-password-reset' | 'user-account-delete'
  // Document Generation
  | 'pdf-generate'
  // Security & Monitoring
  | 'security-violation'
  // Legacy actions (for backward compatibility)
  | 'import' | 'export' | 'confirm' | 'validate';

AuditResult Type

Result types for audit operations:

type AuditResult = 'success' | 'failure' | 'warning' | 'blocked' | 'pending';

AuditDetails Interface

Detailed information for each audit entry:

interface AuditDetails {
  // Core identification
  fileName?: string;
  fileType?: AuditFileType;
  caseNumber?: string;
  confirmationId?: string;
  
  // Validation & Security
  hashValid?: boolean;
  validationErrors: string[];
  securityChecks?: SecurityCheckResults;
  
  // Context & Workflow
  originalExaminerUid?: string;
  reviewingExaminerUid?: string;
  workflowPhase?: WorkflowPhase;
  
  // Performance & Metrics
  performanceMetrics?: PerformanceMetrics;
  
  // Specialized details
  caseDetails?: CaseAuditDetails;
  fileDetails?: FileAuditDetails;
  annotationDetails?: AnnotationAuditDetails;
  sessionDetails?: SessionAuditDetails;
  securityDetails?: SecurityAuditDetails;
  userProfileDetails?: UserProfileAuditDetails;
}

AuditTrail Interface

Complete audit trail for a case or workflow:

interface AuditTrail {
  caseNumber: string;
  workflowId: string;           // Unique identifier linking related entries
  entries: ValidationAuditEntry[];
  summary: AuditSummary;
}

AuditSummary Interface

Summary of audit trail for reporting and compliance:

interface AuditSummary {
  totalEvents: number;
  successfulEvents: number;
  failedEvents: number;
  warningEvents: number;
  workflowPhases: WorkflowPhase[];
  participatingUsers: string[];     // User IDs
  startTimestamp: string;
  endTimestamp: string;
  complianceStatus: 'compliant' | 'non-compliant' | 'pending';
  securityIncidents: number;
}

WorkflowPhase Type

Workflow phases for tracking different types of forensic activities:

type WorkflowPhase = 
  | 'casework'           // Case, notes, image, and pdf related actions
  | 'case-export'        // Only case exporting
  | 'case-import'        // Only case importing  
  | 'confirmation'       // Only confirmation-related activity
  | 'user-management';   // User login, logout, profile management, account activities

Core Annotation Types

AnnotationData Interface

The comprehensive data structure for all annotation information:

interface AnnotationData {
  leftCase: string;
  rightCase: string;
  leftItem: string;
  rightItem: string;
  caseFontColor?: string;
  classType?: 'Bullet' | 'Cartridge Case' | 'Other';
  customClass?: string;
  classNote?: string;
  indexType?: 'number' | 'color';
  indexNumber?: string;
  indexColor?: string;
  supportLevel?: 'ID' | 'Exclusion' | 'Inconclusive';
  hasSubclass?: boolean;
  includeConfirmation: boolean;
  additionalNotes?: string;
  boxAnnotations?: BoxAnnotation[];
  updatedAt: string;
}

BoxAnnotation Interface

Individual box annotation structure with percentage-based coordinates (defined in app/types/annotations.ts):

interface BoxAnnotation {
  id: string;
  x: number;         // Percentage 0-100
  y: number;         // Percentage 0-100
  width: number;     // Percentage 0-100
  height: number;    // Percentage 0-100
  color: string;     // Hex color code
  label?: string;    // Optional label text
  timestamp: string; // Creation timestamp (ISO 8601 format)
}

User Management Types

UserData Interface

Core user profile and permissions structure:

interface UserData {
  uid: string;
  email: string | null;
  firstName: string;
  lastName: string;
  company: string;
  permitted: boolean;
  cases: Array<{
    caseNumber: string;
    createdAt: string;
  }>;
  readOnlyCases?: Array<{
    caseNumber: string;
    importedAt: string;
    originalExportDate: string;
    originalExportedBy: string;
    sourceHash?: string;
    isReadOnly: true;
  }>;
  createdAt: string;
  updatedAt?: string;
}

UserLimits Interface

User account limitations and quotas:

interface UserLimits {
  maxCases: number;
  maxFilesPerCase: number;
}

File Management Types

FileData Interface

Core file information structure:

interface FileData {
  id: string;
  originalFilename: string;
  uploadedAt: string;
}

FileUploadResponse Interface

Cloudflare Images API response structure:

interface FileUploadResponse {
  success: boolean;
  result: {
    id: string;
    filename: string;
    uploaded: string;
    requireSignedURLs: boolean;
    variants: string[];
  };
  errors: Array<{
    code: number;
    message: string;
  }>;
  messages: string[];
}

ImageUploadResponse Interface

Image upload response wrapper (extends FileUploadResponse):

interface ImageUploadResponse {
  success: boolean;
  result: FileUploadResponse['result'];
  errors: FileUploadResponse['errors'];
  messages: FileUploadResponse['messages'];
}

Case Management Types

CaseData Interface

Case structure with associated files:

interface CaseData {
  createdAt: string;
  caseNumber: string;
  files: FileData[];
}

CaseActionType

Case operation type definition for UI state management:

type CaseActionType = 'loaded' | 'created' | 'deleted' | null;

CasesToDelete Interface

Structure for batch case deletion operations:

interface CasesToDelete {
  casesToDelete: string[];
}

Case Export Types

CaseExportData Interface

Complete case export data structure for single case exports:

interface CaseExportData {
  metadata: {
    caseNumber: string;
    exportDate: string;
    exportedBy: string | null;
    striaeExportSchemaVersion: string;
    totalFiles: number;
  };
  files: Array<{
    fileData: FileData;
    annotations?: AnnotationData;
    hasAnnotations: boolean;
  }>;
  summary?: {
    filesWithAnnotations: number;
    filesWithoutAnnotations: number;
    totalBoxAnnotations: number;
    lastModified?: string;
    exportError?: string;
  };
}

AllCasesExportData Interface

Comprehensive export data structure for bulk case exports:

interface AllCasesExportData {
  metadata: {
    exportDate: string;
    exportedBy: string | null;
    striaeExportSchemaVersion: string;
    totalCases: number;
    totalFiles: number;
    totalAnnotations: number;
  };
  cases: CaseExportData[];
  summary?: {
    casesWithFiles: number;
    casesWithAnnotations: number;
    casesWithoutFiles: number;
    lastModified?: string;
  };
}

ExportFormat Type

Export format type definition:

export type ExportFormat = 'json' | 'csv';

ExportOptions Interface

Configuration options for case export operations:

interface ExportOptions {
  includeAnnotations?: boolean;
  includeMetadata?: boolean;
}

Export Features:

  • Format Support: JSON, CSV/Excel, and ZIP export formats

  • ZIP Export with Images: Single case exports can include associated image files packaged in ZIP format

  • Comprehensive Data: All annotation fields including case identifiers, colors, classifications, and box annotations

  • Bulk Operations: Export all cases with progress tracking and error handling

  • Excel Multi-Worksheet: CSV format creates Excel files with multiple worksheets for bulk exports

  • Split Box Annotations: Each box annotation gets its own row in CSV/Excel for better data analysis

  • Metadata Rich: Complete export metadata including timestamps, user info, and summary statistics

  • Error Handling: Graceful handling of failed case exports with detailed error information

  • Progress Tracking: Real-time progress updates for ZIP generation and image downloads

Case Import Types

CaseImportProps Interface

Props interface for the main case import component:

interface CaseImportProps {
  isOpen: boolean;
  onClose: () => void;
  onImportComplete?: (result: ImportResult | ConfirmationImportResult) => void;
}

ImportOptions Interface

Configuration options for case import operations:

interface ImportOptions {
  overwriteExisting?: boolean;
  validateIntegrity?: boolean;
  preserveTimestamps?: boolean;
}

ImportResult Interface

Result structure returned from case import operations:

interface ImportResult {
  success: boolean;
  caseNumber: string;
  isReadOnly: boolean;
  filesImported: number;
  annotationsImported: number;
  errors?: string[];
  warnings?: string[];
}

ConfirmationImportResult Interface

Result structure returned from confirmation import operations:

interface ConfirmationImportResult {
  success: boolean;
  caseNumber: string;
  confirmationsImported: number;
  imagesUpdated: number;
  errors?: string[];
  warnings?: string[];
}

ReadOnlyCaseMetadata Interface

Metadata structure for imported read-only cases:

interface ReadOnlyCaseMetadata {
  caseNumber: string;
  importedAt: string;
  originalExportDate: string;
  originalExportedBy: string;
  sourceHash?: string;
  isReadOnly: true;
}

CaseImportPreview Interface

Preview information generated during ZIP parsing before import:

interface CaseImportPreview {
  caseNumber: string;
  fileCount: number;
  annotationCount: number;
  exportDate: string;
  exportedBy: string;
  hasImages: boolean;
  canImport: boolean;
  warnings: string[];
}

Import Features:

  • Complete ZIP Package Import: Full case data and image import from exported ZIP packages

  • Read-Only Protection: Imported cases are automatically set to read-only mode for secure review

  • Duplicate Prevention: Prevents import if user was the original case analyst

  • Progress Tracking: Multi-stage progress reporting with detailed status updates

  • Image Integration: Automatic upload and association of all case images

  • Metadata Preservation: Complete preservation of original export metadata and timestamps

  • Data Integrity: Comprehensive validation of ZIP contents and case data structure

CSV/Excel Export Details:

  • Single Case CSV: Comprehensive CSV with individual rows for each box annotation

  • Bulk Export Excel: Multi-worksheet Excel file with summary sheet and individual case sheets

  • Complete Data Parity: CSV/Excel exports contain identical data to JSON exports

  • Enhanced Box Annotations: Includes coordinates, colors, and timestamps (label removed)

  • Classification Data: Full support for case identifiers, color schemes, and forensic classifications

  • Optimized Layout: File metadata appears only on first row per file, subsequent rows contain only box data

ZIP Export Functionality:

  • Single Case Only: ZIP exports are restricted to individual cases to manage file size

  • Image Inclusion: All associated image files packaged with original filenames preserved

  • Data File: Selected format (JSON or CSV) included in ZIP package

  • README Generation: Automatic README.txt with case summary and statistics

  • Progress Feedback: Real-time progress updates during ZIP creation and image downloads

  • Error Recovery: Graceful handling of individual image download failures

  • JSZip Integration: Browser-based ZIP generation using JSZip library

Centralized Type Management

Type Definition Location: All interfaces are centrally defined in app/types/ with barrel exports from app/types/index.ts:

// Barrel export structure
export * from './annotations';  // AnnotationData, BoxAnnotation
export * from './user';        // UserData, UserLimits
export * from './file';        // FileData, FileUploadResponse, ImageUploadResponse
export * from './case';        // CaseData, CaseMetadata, CaseActionType, CaseExportData, AllCasesExportData

Usage Patterns:

  • Centralized Imports: import { UserData, FileData, AnnotationData } from '~/types';

  • Component Props: All component interfaces extend or use centralized types

  • Worker APIs: Type validation based on shared interface definitions

  • PDF Generation: Type-safe data flow from frontend through workers

  • Data Storage: Structured data persistence with comprehensive type validation

Benefits:

  • Single source of truth for all data structures

  • Type safety across entire application stack

  • Consistent API contracts between frontend and workers

  • Easier refactoring and maintenance with centralized type management

  • Compile-time error detection for data structure changes

  • Comprehensive coverage of all application domains (user, file, case, annotation)

  • Utility types for common patterns (loading states, API responses, pagination)

SDK Examples

JavaScript/TypeScript Client

class StriaeAPI {
  constructor(private apiKey: string, private baseUrl: string) {}

  async getUser(userUid: string): Promise<UserData> {
    const response = await fetch(`${this.baseUrl}/${userUid}`, {
      headers: {
        'X-Custom-Auth-Key': this.apiKey,
        'Content-Type': 'application/json'
      }
    });
    
    if (!response.ok) {
      throw new Error(`API Error: ${response.status}`);
    }
    
    return response.json();
  }

  async uploadImage(file: File): Promise<UploadResult> {
    const formData = new FormData();
    formData.append('file', file);

    const response = await fetch(`${this.baseUrl}`, {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${this.apiKey}`
      },
      body: formData
    });

    return response.json();
  }
}

Error Handling Example

try {
  const userData = await api.getUser(userUid);
  console.log('User data:', userData);
} catch (error) {
  if (error.status === 404) {
    console.log('User not found');
  } else if (error.status === 401) {
    console.log('Authentication failed');
  } else {
    console.error('API error:', error);
  }
}
Updated on