Overview
Robust error handling is crucial when integrating with the Zyrix Admin API. This guide covers common error scenarios, debugging techniques, and best practices for building reliable integrations.Common Error Scenarios
Permission Errors
The most common errors relate to insufficient permissions:Copy
local function handlePermissionError(staffId, action, status)
local messages = {
no_permission = string.format("You don't have permission to %s", action),
insufficient_rank = "Your staff rank is too low for this action",
invalid_staff = "Invalid staff credentials"
}
local message = messages[status] or "Permission error occurred"
TriggerClientEvent('notification', staffId, message)
end
-- Usage
local success, status = exports['zyrix_admin']:BanPlayer(staffId, targetId, 3600, reason)
if not success and string.find(status, 'permission') then
handlePermissionError(staffId, 'ban players', status)
end
Player Not Found Errors
Handle cases where target players are offline or invalid:Copy
local function validatePlayer(playerId)
if not playerId or playerId < 1 then
return false, "Invalid player ID"
end
if not GetPlayerName(playerId) then
return false, "Player not found or offline"
end
return true
end
-- Usage before API calls
local valid, error = validatePlayer(targetId)
if not valid then
print("Validation failed:", error)
return
end
local success, status = exports['zyrix_admin']:HealPlayer(staffId, targetId)
Rate Limiting
Handle rate limiting for bulk operations:Copy
local function performBulkAction(staffId, playerIds, actionFunction, actionName)
local results = {}
local rateLimited = 0
for _, playerId in ipairs(playerIds) do
local success, status = actionFunction(staffId, playerId)
if status == 'rate_limited' then
rateLimited = rateLimited + 1
Wait(1000) -- Wait 1 second before retry
success, status = actionFunction(staffId, playerId)
end
results[playerId] = {success = success, status = status}
end
if rateLimited > 0 then
print(string.format("Rate limited %d times during bulk %s", rateLimited, actionName))
end
return results
end
Error Handling Patterns
Try-Catch Pattern
Implement a try-catch style error handler:Copy
local function tryApiCall(apiFunction, ...)
local success, status, data = apiFunction(...)
if not success then
return {
success = false,
error = status,
message = "API call failed: " .. tostring(status)
}
end
return {
success = true,
data = data,
status = status
}
end
-- Usage
local result = tryApiCall(exports['zyrix_admin'].TeleportPlayer, staffId, targetId, coords)
if not result.success then
print("Teleport failed:", result.message)
else
print("Teleport successful")
end
Retry Logic
Implement automatic retries for transient errors:Copy
local function apiCallWithRetry(apiFunction, maxRetries, ...)
local args = {...}
for attempt = 1, maxRetries do
local success, status, data = apiFunction(table.unpack(args))
if success then
return success, status, data
end
-- Retry on specific error types
if status == 'system_error' or status == 'rate_limited' then
if attempt < maxRetries then
Wait(1000 * attempt) -- Exponential backoff
else
break
end
else
-- Don't retry on permission or validation errors
break
end
end
return false, status or 'max_retries_exceeded'
end
-- Usage
local success, status = apiCallWithRetry(exports['zyrix_admin'].BanPlayer, 3, staffId, targetId, 3600, reason)
Validation Helper
Create validation helpers for common parameters:Copy
local Validation = {}
function Validation.validateStaffId(staffId)
if not staffId or type(staffId) ~= 'number' then
return false, 'invalid_staff_id_type'
end
if not GetPlayerName(staffId) then
return false, 'staff_not_found'
end
return true
end
function Validation.validateTargetId(targetId)
if not targetId or type(targetId) ~= 'number' then
return false, 'invalid_target_id_type'
end
if not GetPlayerName(targetId) then
return false, 'target_not_found'
end
return true
end
function Validation.validateDuration(duration)
if not duration or type(duration) ~= 'number' or duration < 0 then
return false, 'invalid_duration'
end
-- Max 30 days
if duration > 2592000 then
return false, 'duration_too_long'
end
return true
end
-- Usage
local function safeBanPlayer(staffId, targetId, duration, reason)
local valid, error = Validation.validateStaffId(staffId)
if not valid then return false, error end
valid, error = Validation.validateTargetId(targetId)
if not valid then return false, error end
valid, error = Validation.validateDuration(duration)
if not valid then return false, error end
return exports['zyrix_admin']:BanPlayer(staffId, targetId, duration, reason)
end
Debugging Techniques
Comprehensive Logging
Implement detailed logging for troubleshooting:Copy
local function debugApiCall(functionName, success, status, ...)
local args = {...}
local timestamp = os.date("%Y-%m-%d %H:%M:%S")
local logEntry = string.format(
"[%s] API Call: %s | Success: %s | Status: %s | Args: %s",
timestamp,
functionName,
tostring(success),
tostring(status),
json.encode(args)
)
print(logEntry)
-- Optionally log to file
-- appendToLogFile("zyrix_api.log", logEntry)
end
-- Wrapper function with debug logging
local function debugBanPlayer(staffId, targetId, duration, reason)
local success, status = exports['zyrix_admin']:BanPlayer(staffId, targetId, duration, reason)
debugApiCall("BanPlayer", success, status, staffId, targetId, duration, reason)
return success, status
end
Status Code Mapping
Create human-readable error messages:Copy
local ERROR_MESSAGES = {
no_permission = "Insufficient permissions for this action",
invalid_staff = "Staff member not found or invalid",
invalid_target = "Target player not found or invalid",
player_not_found = "Player is not currently online",
already_banned = "Player is already banned",
not_banned = "Player is not currently banned",
invalid_duration = "Invalid ban duration specified",
rate_limited = "Action temporarily blocked - please wait",
system_error = "Internal system error - please try again"
}
local function getErrorMessage(status)
return ERROR_MESSAGES[status] or string.format("Unknown error: %s", status)
end
-- Usage
local success, status = exports['zyrix_admin']:KickPlayer(staffId, targetId, reason)
if not success then
local message = getErrorMessage(status)
TriggerClientEvent('notification', staffId, message)
end
Production Best Practices
1. Always Validate Input
Copy
local function validateInputs(staffId, targetId, reason)
if not staffId or not GetPlayerName(staffId) then
return false, "Invalid staff member"
end
if not targetId or not GetPlayerName(targetId) then
return false, "Invalid target player"
end
if not reason or string.len(reason) < 3 then
return false, "Reason must be at least 3 characters"
end
return true
end
2. Implement Circuit Breaker Pattern
Copy
local CircuitBreaker = {
failures = 0,
threshold = 5,
timeout = 30000, -- 30 seconds
lastFailureTime = 0,
isOpen = false
}
function CircuitBreaker:canExecute()
if not self.isOpen then return true end
if GetGameTimer() - self.lastFailureTime > self.timeout then
self.isOpen = false
self.failures = 0
return true
end
return false
end
function CircuitBreaker:onSuccess()
self.failures = 0
self.isOpen = false
end
function CircuitBreaker:onFailure()
self.failures = self.failures + 1
self.lastFailureTime = GetGameTimer()
if self.failures >= self.threshold then
self.isOpen = true
end
end
3. Monitor API Health
Copy
local ApiHealth = {
totalCalls = 0,
successfulCalls = 0,
lastHealthCheck = 0
}
function ApiHealth:recordCall(success)
self.totalCalls = self.totalCalls + 1
if success then
self.successfulCalls = self.successfulCalls + 1
end
end
function ApiHealth:getSuccessRate()
if self.totalCalls == 0 then return 100 end
return (self.successfulCalls / self.totalCalls) * 100
end
function ApiHealth:shouldAlert()
return self.getSuccessRate() < 95 and self.totalCalls > 10
end
Always implement proper error handling in production environments. Unhandled errors can cause script failures and poor user experiences.