385 lines
9.6 KiB
Markdown
385 lines
9.6 KiB
Markdown
# SatLoc API Error Patterns - Complete Reference
|
|
|
|
**Date:** October 3, 2025
|
|
**Purpose:** Document ALL actual SatLoc API error responses discovered through testing
|
|
**Status:** Based on real API testing with invalid credentials and parameters
|
|
|
|
---
|
|
|
|
## Summary
|
|
|
|
The SatLoc API has **THREE DISTINCT error patterns** depending on the type of error:
|
|
|
|
1. **Authentication Errors** (wrong username/password)
|
|
2. **Parameter Validation Errors** (wrong IDs)
|
|
3. **Server Errors** (internal failures)
|
|
|
|
**CRITICAL:** Do NOT confuse authentication errors with parameter validation errors!
|
|
|
|
---
|
|
|
|
## 1. Authentication Errors
|
|
|
|
### Test Scenario: AuthenticateAPIUser with Wrong Credentials
|
|
|
|
**Tested Cases:**
|
|
- Wrong username and password
|
|
- Empty password
|
|
- SQL injection attempts
|
|
- Special characters in credentials
|
|
|
|
**API Response Pattern:**
|
|
```
|
|
HTTP Status: 400
|
|
Status Text: "Invalid Username or Password provide."
|
|
Response Body: "" (empty string, NOT JSON)
|
|
Content-Type: text/html; charset=utf-8
|
|
```
|
|
|
|
**Example Test Result:**
|
|
```javascript
|
|
// Test: Wrong username and password
|
|
{
|
|
status: 400,
|
|
statusText: "Invalid Username or Password provide.",
|
|
data: "" // Empty string!
|
|
}
|
|
```
|
|
|
|
**Detection Pattern:**
|
|
```javascript
|
|
function isAuthenticationError(error) {
|
|
const status = error.response?.status;
|
|
const statusText = error.response?.statusText || '';
|
|
const data = error.response?.data;
|
|
|
|
return status === 400 &&
|
|
data === '' &&
|
|
(statusText.includes('Invalid Username') ||
|
|
statusText.includes('Invalid Password'));
|
|
}
|
|
```
|
|
|
|
**Handling Strategy:**
|
|
- Clear authentication cache
|
|
- Wait 3 seconds (allow for credential propagation)
|
|
- Retry authentication ONCE with fresh credentials
|
|
- If retry fails, throw AppAuthError
|
|
- Worker should retry the task (not send to DLQ)
|
|
|
|
---
|
|
|
|
## 2. Parameter Validation Errors
|
|
|
|
### Test Scenario: API Methods with Wrong IDs
|
|
|
|
**Affected Endpoints:**
|
|
- `GetAircraftList` - with wrong userId or companyId
|
|
- `GetAircraftLogs` - with wrong userId or aircraftId
|
|
- Other data access endpoints
|
|
|
|
**API Response Pattern:**
|
|
```
|
|
HTTP Status: 400
|
|
Status Text: "Bad Request"
|
|
Response Body: { "message": "The request is invalid." }
|
|
Content-Type: application/json; charset=utf-8
|
|
```
|
|
|
|
**Example Test Results:**
|
|
|
|
```javascript
|
|
// Test 1: GetAircraftList with wrong userId
|
|
{
|
|
status: 400,
|
|
statusText: "Bad Request",
|
|
data: {
|
|
"message": "The request is invalid."
|
|
}
|
|
}
|
|
|
|
// Test 2: GetAircraftList with wrong companyId
|
|
{
|
|
status: 400,
|
|
statusText: "Bad Request",
|
|
data: {
|
|
"message": "The request is invalid."
|
|
}
|
|
}
|
|
|
|
// Test 3: GetAircraftList with empty userId
|
|
{
|
|
status: 400,
|
|
statusText: "Bad Request",
|
|
data: {
|
|
"message": "The request is invalid."
|
|
}
|
|
}
|
|
|
|
// Test 4: GetAircraftLogs with wrong userId
|
|
{
|
|
status: 400,
|
|
statusText: "Bad Request",
|
|
data: {
|
|
"message": "The request is invalid."
|
|
}
|
|
}
|
|
|
|
// Test 5: GetAircraftLogs with wrong aircraftId
|
|
{
|
|
status: 400,
|
|
statusText: "Bad Request",
|
|
data: {
|
|
"message": "The request is invalid."
|
|
}
|
|
}
|
|
```
|
|
|
|
**Detection Pattern:**
|
|
```javascript
|
|
function isParameterValidationError(error) {
|
|
const status = error.response?.status;
|
|
const statusText = error.response?.statusText || '';
|
|
const data = error.response?.data;
|
|
|
|
return status === 400 &&
|
|
typeof data === 'object' &&
|
|
data.message === 'The request is invalid.' &&
|
|
statusText === 'Bad Request';
|
|
}
|
|
```
|
|
|
|
**Handling Strategy:**
|
|
- Do NOT clear authentication cache (credentials are fine!)
|
|
- Do NOT retry (the IDs are wrong, retry won't help)
|
|
- Log error with context (which IDs are wrong)
|
|
- Return error to caller with clear message
|
|
- Worker should NOT retry (data issue, not transient)
|
|
|
|
**IMPORTANT:** These are NOT authentication errors! The credentials are valid, but the resource IDs (userId, companyId, aircraftId) don't exist or don't match.
|
|
|
|
---
|
|
|
|
## 3. Server Errors
|
|
|
|
### Test Scenario: API Methods Triggering Server Failures
|
|
|
|
**Affected Endpoints:**
|
|
- `UploadJobData` - with wrong userId/companyId/aircraftId
|
|
- Potentially any endpoint under certain conditions
|
|
|
|
**API Response Pattern:**
|
|
```
|
|
HTTP Status: 500
|
|
Status Text: "Internal Server Error"
|
|
Response Body: "" (empty string)
|
|
Content-Type: text/html; charset=utf-8
|
|
```
|
|
|
|
**Example Test Results:**
|
|
|
|
```javascript
|
|
// Test 6: UploadJobData with wrong userId and companyId
|
|
{
|
|
status: 500,
|
|
statusText: "Internal Server Error",
|
|
data: "" // Empty string!
|
|
}
|
|
|
|
// Test 7: UploadJobData with wrong aircraftId
|
|
{
|
|
status: 500,
|
|
statusText: "Internal Server Error",
|
|
data: "" // Empty string!
|
|
}
|
|
```
|
|
|
|
**Special Case - Empty Username in Authentication:**
|
|
```javascript
|
|
// Test: AuthenticateAPIUser with empty username
|
|
{
|
|
status: 500,
|
|
statusText: "Internal Server Error",
|
|
data: {
|
|
"message": "An error has occurred."
|
|
}
|
|
}
|
|
```
|
|
|
|
**Detection Pattern:**
|
|
```javascript
|
|
function isServerError(error) {
|
|
const status = error.response?.status;
|
|
return status >= 500;
|
|
}
|
|
```
|
|
|
|
**Handling Strategy:**
|
|
- Log error with full context
|
|
- Do NOT clear authentication cache (server issue, not credentials)
|
|
- Allow worker to retry with exponential backoff
|
|
- If persistent, send alert to monitoring
|
|
- May be transient (server restart, network issue, etc.)
|
|
|
|
---
|
|
|
|
## Error Decision Tree
|
|
|
|
```
|
|
Is error.response.status === 400?
|
|
├─ YES: Is response.data an empty string?
|
|
│ ├─ YES: Does statusText contain "Invalid Username" or "Invalid Password"?
|
|
│ │ ├─ YES: → AUTHENTICATION ERROR
|
|
│ │ └─ NO: → Unknown 400 error
|
|
│ └─ NO: Is response.data.message === "The request is invalid."?
|
|
│ ├─ YES: → PARAMETER VALIDATION ERROR
|
|
│ └─ NO: → Unknown 400 error
|
|
└─ NO: Is error.response.status >= 500?
|
|
├─ YES: → SERVER ERROR
|
|
└─ NO: → Check other status codes (401, 403, 404, etc.)
|
|
```
|
|
|
|
---
|
|
|
|
## Implementation in Code
|
|
|
|
### isAuthError() Method
|
|
|
|
```javascript
|
|
/**
|
|
* Check if error is authentication-related (wrong credentials)
|
|
* NOT parameter validation (wrong IDs)
|
|
*/
|
|
isAuthError(error) {
|
|
if (!error) return false;
|
|
|
|
// Check if error is AppAuthError (thrown by our authenticate() method)
|
|
if (error.name === 'AppAuthError' || error.constructor.name === 'AppAuthError') {
|
|
return true;
|
|
}
|
|
|
|
const status = error.response?.status;
|
|
const statusText = (error.response?.statusText || '').toLowerCase();
|
|
const responseData = error.response?.data;
|
|
|
|
// Authentication endpoint failure: HTTP 400 + empty string + specific statusText
|
|
if (status === 400 && responseData === '' &&
|
|
(statusText.includes('invalid username') ||
|
|
statusText.includes('invalid password') ||
|
|
statusText.includes('username or password'))) {
|
|
return true;
|
|
}
|
|
|
|
// NOTE: HTTP 400 with JSON response {"message": "The request is invalid."}
|
|
// is NOT an auth error - it's parameter validation (wrong IDs)
|
|
|
|
// Check error message from our code
|
|
const message = (error.message || '').toLowerCase();
|
|
if (message.includes('authentication failed') ||
|
|
message.includes('wrong_credential') ||
|
|
message.includes('invalid credential')) {
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
```
|
|
|
|
### Error Handling in API Methods
|
|
|
|
```javascript
|
|
async getAircraftList(customerId) {
|
|
try {
|
|
const authData = await this.getCachedAuth(customerId);
|
|
const response = await axios.get(
|
|
`${this.config.apiEndpoint}/GetAircraftList`,
|
|
{
|
|
params: {
|
|
userId: authData.userId,
|
|
companyId: authData.companyId
|
|
},
|
|
...this.requestConfig
|
|
}
|
|
);
|
|
|
|
return {
|
|
success: true,
|
|
aircraft: response.data || []
|
|
};
|
|
|
|
} catch (error) {
|
|
const status = error.response?.status;
|
|
const data = error.response?.data;
|
|
|
|
let errorMessage = error.message;
|
|
|
|
// Provide specific error messages based on error type
|
|
if (status === 400 && typeof data === 'object' && data.message) {
|
|
errorMessage = `Invalid parameters: ${data.message} (check userId/companyId)`;
|
|
} else if (status >= 500) {
|
|
errorMessage = `SatLoc server error: ${error.message}`;
|
|
} else if (this.isAuthError(error)) {
|
|
errorMessage = `Authentication failed: ${error.message}`;
|
|
}
|
|
|
|
pino.debug('SatLoc GetAircraftList failed',
|
|
`customer=${customerId}, status=${status}, error=${errorMessage}`);
|
|
|
|
return {
|
|
success: false,
|
|
error: errorMessage,
|
|
isAuthError: this.isAuthError(error),
|
|
isServerError: status >= 500
|
|
};
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Testing Commands
|
|
|
|
### Test Authentication Errors
|
|
```bash
|
|
node tests/test_satloc_errors_simple.js
|
|
```
|
|
|
|
### Test All API Endpoints with Invalid Data
|
|
```bash
|
|
node tests/test_satloc_all_endpoints.js
|
|
```
|
|
|
|
---
|
|
|
|
## Key Takeaways
|
|
|
|
1. **HTTP 400 does NOT always mean authentication error!**
|
|
- Empty string response + specific statusText = Authentication error
|
|
- JSON response with "The request is invalid." = Parameter validation error
|
|
|
|
2. **Parameter validation errors should NOT trigger cache clearing**
|
|
- The credentials are valid
|
|
- The resource IDs are wrong
|
|
- Retrying won't help
|
|
|
|
3. **Server errors (HTTP 500) may be transient**
|
|
- Allow worker retry with backoff
|
|
- Monitor for persistent failures
|
|
|
|
4. **Always check response body type and content**
|
|
- Empty string vs JSON object changes the meaning
|
|
- statusText provides additional context
|
|
|
|
5. **Test with actual API calls, not assumptions!**
|
|
- "Standard" REST patterns don't always apply
|
|
- Each API has its own error conventions
|
|
|
|
---
|
|
|
|
## References
|
|
|
|
- Test script: `test_satloc_errors_simple.js` - Authentication errors
|
|
- Test script: `test_satloc_all_endpoints.js` - All endpoint errors
|
|
- Implementation: `services/satloc_service.js` - Error detection and handling
|
|
- Documentation: `docs/SATLOC_API_ACTUAL_BEHAVIOR.md` - Authentication endpoint behavior
|