mem-dashboard / docs/api_endpoints.md

API Endpoints Documentation

MEM dashboard

Last updated: 4/16/2026GitHubMEM Dashboard

API Endpoints Documentation

This document provides comprehensive documentation for the NocoDB API endpoints used by the MEM Dashboard frontend application.

Overview

The MEM Dashboard frontend connects to a NocoDB instance that exposes PostgreSQL database tables via REST API. NocoDB automatically creates API endpoints for each table in the database, eliminating the need for a custom backend API.

Base Configuration

Environment Variables

The following environment variables must be configured for API access:

VITE_API_BASE_URL='https://nocodb.mem.gov.om/api/v2/tables'
VITE_API_TOKEN='GW_ZXfUgOhV4LhcMdzwaPE_qt48MDpXKzcnCk4ab'
VITE_API_ENDPOINT_UNITS='/mwmtkgvc4uo7b4e/records'
VITE_API_ENDPOINT_UNITS_WORKFORCE='/mqgoz7qkhobtod3/records'

Authentication

All API requests require authentication via the xc-token header:

headers: {
  "xc-token": "GW_ZXfUgOhV4LhcMdzwaPE_qt48MDpXKzcnCk4ab"
}

Base URL Structure

https://nocodb.mem.gov.om/api/v2/tables/{table_id}/records

Where {table_id} is the unique identifier assigned by NocoDB for each table.

API Endpoints

1. Units Endpoint

Retrieves drilling units data including rigs and hoists.

Endpoint: /mwmtkgvc4uo7b4e/records
Full URL: https://nocodb.mem.gov.om/api/v2/tables/mwmtkgvc4uo7b4e/records
Method: GET

Query Parameters

ParameterTypeDefaultDescription
offsetnumber0Number of records to skip for pagination
limitnumber1000Maximum number of records to return
wherestring-Filter conditions (see Filtering section)

Response Format

{
  "list": [
    {
      "id": "string",
      "operator_name": "string",
      "contract_type": "string",
      "unit_number": "string", 
      "block_number": "string",
      "field_name": "string",
      "contractor_name": "string",
      "contractor_name_short": "string",
      "contract_number": "string",
      "total_workforce": "string",
      "total_workforce_omani": "string",
      "purpose": "Production" | "Exploration",
      "contract_amount": number,
      "planned_date": "YYYY-MM-DD",
      "awarded_date": "YYYY-MM-DD", 
      "commencement_date": "YYYY-MM-DD",
      "expiry_date": "YYYY-MM-DD",
      "stacked_start_date": "YYYY-MM-DD",
      "stacked_end_date": "YYYY-MM-DD",
      "terminated_date": "YYYY-MM-DD",
      "extension_duration_in_months": number
    }
  ],
  "pageInfo": {
    "totalRows": number,
    "page": number,
    "pageSize": number,
    "isFirstPage": boolean,
    "isLastPage": boolean
  }
}

Example Request

const response = await fetch('https://nocodb.mem.gov.om/api/v2/tables/mwmtkgvc4uo7b4e/records?offset=0&limit=1000', {
  headers: {
    "xc-token": "GW_ZXfUgOhV4LhcMdzwaPE_qt48MDpXKzcnCk4ab"
  }
});
const data = await response.json();

Frontend Usage

The frontend uses this endpoint through the useFetchUnitsQuery hook:

// web/src/hooks/units/useFetchUnitsQuery.ts
const fetchUnits = async (): Promise<Unit[]> => {
  const res = await callApi<{ list: Unit[] }>(
    import.meta.env.VITE_API_ENDPOINT_UNITS,
    { offset: 0, limit: 1000 }
  );
  return res.list;
};

2. Units Workforce Endpoint

Retrieves workforce data associated with drilling units.

Endpoint: /mqgoz7qkhobtod3/records
Full URL: https://nocodb.mem.gov.om/api/v2/tables/mqgoz7qkhobtod3/records
Method: GET

Query Parameters

ParameterTypeDefaultDescription
offsetnumber0Number of records to skip for pagination
limitnumber1000Maximum number of records to return
wherestring-Complex filter conditions for workforce data

Response Format

{
  "list": [
    {
      "operator_name": "string",
      "contract_number": "string",
      "company_name": "string",
      "year_period": "string",
      "skill_category_name": "string", 
      "skill_sub_category_name": "string",
      "head_count": number,
      "icv_sub_element": "Omani" | "Expat"
    }
  ],
  "pageInfo": {
    "totalRows": number,
    "page": number,
    "pageSize": number,
    "isFirstPage": boolean,
    "isLastPage": boolean
  }
}

Example Request with Filtering

const contractClause = "(contract_number,in,PDO-12345,OQ-67890)";
const contractorClause = "(company_name,in,Schlumberger,Halliburton)";
const whereClause = `${contractClause}~and${contractorClause}`;

const response = await fetch(`https://nocodb.mem.gov.om/api/v2/tables/mqgoz7qkhobtod3/records?offset=0&limit=1000&where=${whereClause}`, {
  headers: {
    "xc-token": "GW_ZXfUgOhV4LhcMdzwaPE_qt48MDpXKzcnCk4ab"
  }
});

Frontend Usage

The frontend implements complex filtering and pagination for this endpoint:

// web/src/hooks/units/useFetchUnitsWorkforceQuery.ts
const fetchUnitsWorkforce = async (units: Unit[]): Promise<UnitWorkforce[]> => {
  // Build complex where clause
  const contractClause = `(contract_number,in,${units
    .map((unit) => `${unit.operator_name}-${unit.contract_number}`)
    .join(",")})`;
  
  const contractorClause = `(company_name,in,${units
    .map((unit) => unit.contractor_name)
    .join(",")})`;
  
  const whereClause = `${contractClause}~and${contractorClause}`;
  
  // Handle pagination for large datasets
  let offset = 0;
  let allResults: UnitWorkforce[] = [];
  
  while (true) {
    const res = await callApi<{
      list: UnitWorkforce[];
      pageInfo: { isLastPage: boolean; };
    }>(import.meta.env.VITE_API_ENDPOINT_UNITS_WORKFORCE, {
      offset,
      limit: 1000,
      where: whereClause,
    });
    
    allResults = allResults.concat(res.list);
    if (res.pageInfo.isLastPage) break;
    
    offset += 1000;
  }
  
  return allResults;
};

Filtering and Query Syntax

NocoDB uses a specific syntax for filtering records in the where parameter.

Basic Operators

OperatorSyntaxExample
Equal(field,eq,value)(operator_name,eq,PDO)
Not Equal(field,neq,value)(status,neq,terminated)
In(field,in,value1,value2)(contract_type,in,rig,hoist)
Like(field,like,%value%)(field_name,like,%north%)
Greater Than(field,gt,value)(contract_amount,gt,1000000)
Less Than(field,lt,value)(total_workforce,lt,100)

Logical Operators

OperatorSyntaxExample
ANDcondition1~and~condition2(operator_name,eq,PDO)~and~(status,eq,active)
ORcondition1~or~condition2(contract_type,eq,rig)~or~(contract_type,eq,hoist)

Complex Filter Example

// Filter for active PDO rigs with workforce > 50
const whereClause = "(operator_name,eq,PDO)~and~(contract_type,eq,rig)~and~(total_workforce,gt,50)";

Pagination

Implementation Pattern

Both endpoints support pagination through offset and limit parameters. The frontend implements automatic pagination handling:

let offset = 0;
const limit = 1000;
let allResults = [];

while (true) {
  const response = await callApi(endpoint, { offset, limit, where });
  allResults = allResults.concat(response.list);
  
  if (response.pageInfo.isLastPage) break;
  offset += limit;
}

Page Info Object

interface PageInfo {
  totalRows: number;      // Total number of records
  page: number;          // Current page number
  pageSize: number;      // Number of records per page
  isFirstPage: boolean;  // Whether this is the first page
  isLastPage: boolean;   // Whether this is the last page
}

Error Handling

Common HTTP Status Codes

StatusMeaningAction
200SuccessProcess response data
401UnauthorizedCheck API token
403ForbiddenVerify permissions
404Not FoundCheck endpoint URL
500Server ErrorRetry or contact admin

Frontend Error Handling

export async function callApi<T>(
  url: string,
  params?: Record<string, string | number | boolean>,
): Promise<T> {
  try {
    const response = await instance.get(url, { params });
    return response.data as T;
  } catch (error) {
    console.error("API call failed:", error);
    throw error;
  }
}

Data Types and Interfaces

Unit Interface

interface Unit {
  id: string;
  operator_name: string;
  contract_type: string; // "rig" or "hoist"
  unit_number: string;
  block_number: string;
  field_name: string;
  contractor_name: string;
  contractor_name_short: string;
  contract_number: string;
  total_workforce: string; // numeric string
  total_workforce_omani: string; // numeric string
  purpose: "Production" | "Exploration";
  
  contract_amount?: number;
  planned_date?: string; // YYYY-MM-DD
  awarded_date?: string; // YYYY-MM-DD
  commencement_date?: string; // YYYY-MM-DD
  expiry_date?: string; // YYYY-MM-DD
  stacked_start_date?: string; // YYYY-MM-DD
  stacked_end_date?: string; // YYYY-MM-DD
  terminated_date?: string; // YYYY-MM-DD
  extension_duration_in_months?: number;
}

UnitWorkforce Interface

interface UnitWorkforce {
  operator_name: string;
  contract_number: string;
  company_name: string;
  year_period: string; // "YYYY-QX" format (e.g., "2024-Q4")
  skill_category_name: string; // e.g., "Professional"
  skill_sub_category_name: string; // e.g., "Driver - LV"
  head_count: number;
  icv_sub_element: "Omani" | "Expat";
}

Frontend Integration Examples

React Query Integration

The frontend uses React Query for data fetching and caching:

// Basic query hook
export const useFetchUnitsQuery = () => {
  return useQuery({
    queryKey: ["units"],
    queryFn: fetchUnits,
  });
};

// Usage in components
const { data: units, isLoading, error } = useFetchUnitsQuery();

Processing and Filtering

The frontend processes raw API data for display:

// Processing units with status calculation
const processedUnits = units?.map(unit => ({
  ...unit,
  contractStatus: calculateStatus(unit),
  coords: generateCoordinates(unit, blocks),
  completionPercentage: calculateCompletion(unit)
}));

Development Notes

Environment Setup

  1. Ensure all VITE_API_* environment variables are properly configured
  2. NocoDB table IDs may change if database is recreated
  3. API token should be kept secure and not committed to version control

Performance Considerations

  1. Use pagination for large datasets (limit: 1000 recommended)
  2. Implement proper error handling and retry logic
  3. Cache responses using React Query for better performance
  4. Batch related API calls when possible

Security

  1. Never expose API tokens in client-side code in production
  2. Consider implementing API token rotation
  3. Use HTTPS for all API communications
  4. Validate and sanitize all user inputs before sending to API

Troubleshooting

Common Issues

  1. 401 Unauthorized: Check if xc-token is correctly set
  2. Empty Results: Verify table IDs in environment variables
  3. Timeout Errors: Reduce limit parameter or implement better pagination
  4. CORS Errors: Ensure NocoDB is configured to allow frontend domain

Debugging Tips

  1. Use browser network tab to inspect actual API requests
  2. Check console for detailed error messages
  3. Verify environment variables are loaded correctly
  4. Test API endpoints directly using tools like Postman or curl