Exercise 7: Error Handling and Actions
This exercise shows simple error handling patterns that you can extend for your own applications with various
HTTP status codes.
7.1 Basic Error Handling Examples
This exercise shows simple error handling patterns that you can extend for your own applications. We'll implement basic validation and error simulation in the mockserver.
Update
webapp/localService/mainService/data/Books.js
with basic error examples:
ex7/webapp/localService/mainService/data/Books.js
View on GitHub ↗
case 'setDiscount':
// Simple validation example - discount cannot exceed 90%
if (actionData.percentage > 90) {
this.throwError('Discount cannot exceed 90%', 400, {
error: {
code: 'INVALID_DISCOUNT',
message: 'Company policy: Maximum discount is 90%',
},
});
}
// Simple 500 error simulation - uncomment to test
// if (actionData.percentage === 42) {
// this.throwError('Simulated server error', 500);
// }
// Normal business logic continues...
const currentEntries = await this.base.fetchEntries(keys);
// ... rest of discount logic
7.2 Common Error Types
The mockserver supports standard HTTP error codes:
| Status Code | Error Type | Use Case | Example |
|---|---|---|---|
| 400 | Bad Request | Input validation failures | Invalid discount percentage |
| 404 | Not Found | Entity doesn't exist | Book ID not found |
| 422 | Unprocessable Entity | Business rule violations | Stock insufficient for operation |
| 500 | Internal Server Error | System failures | Database connection failed |
| 501 | Not Implemented | Action not supported | Unimplemented action name |
7.3 Complete Error Implementation Example
Here's a more comprehensive example showing various error scenarios:
module.exports = {
executeAction: async function (actionDefinition, actionData, keys, odataRequest) {
console.log('Executing action:', actionDefinition.name);
switch (actionDefinition.name) {
case 'setDiscount':
// Input validation - 400 Bad Request
if (!actionData.percentage || actionData.percentage < 0) {
this.throwError('Discount percentage is required and must be positive', 400, {
error: {
code: 'INVALID_INPUT',
message: 'Percentage must be a positive number',
},
});
}
// Business rule validation - 400 Bad Request
if (actionData.percentage > 90) {
this.throwError('Discount cannot exceed 90%', 400, {
error: {
code: 'INVALID_DISCOUNT',
message: 'Company policy: Maximum discount is 90%',
},
});
}
// Entity not found - 404 Not Found
const currentEntries = await this.base.fetchEntries(keys);
if (!currentEntries || currentEntries.length === 0) {
this.throwError('Book not found', 404, {
error: {
code: 'ENTITY_NOT_FOUND',
message: `Book with ID ${keys.ID} does not exist`,
},
});
}
// Business logic validation - 422 Unprocessable Entity
const currentBook = currentEntries[0];
if (currentBook.stock <= 0) {
this.throwError('Cannot apply discount to out-of-stock items', 422, {
error: {
code: 'BUSINESS_RULE_VIOLATION',
message: 'Discounts are not allowed for items with zero stock',
},
});
}
// Simulated system error - 500 Internal Server Error
if (actionData.percentage === 42) {
this.throwError('Simulated server error for testing', 500, {
error: {
code: 'INTERNAL_ERROR',
message: 'Database connection temporarily unavailable',
},
});
}
// Normal business logic
const discountMultiplier = (100 - actionData.percentage) / 100;
const newPrice = Math.round(currentBook.price * discountMultiplier * 100) / 100;
await this.base.updateEntry(keys, { price: newPrice });
return {
message: `${actionData.percentage}% discount applied successfully`,
newPrice: newPrice,
originalPrice: currentBook.price,
discountAmount: currentBook.price - newPrice,
};
case 'promoteBook':
// ... existing promote logic ...
break;
default:
// 501 Not Implemented
this.throwError(`Action ${actionDefinition.name} not implemented`, 501, {
error: {
code: 'NOT_IMPLEMENTED',
message: `The action '${actionDefinition.name}' is not supported by this service`,
},
});
}
},
};
7.4 Testing Error Scenarios
Start the application:
# from folder ex7
npm run start-mock
# or from root folder
npm run start:ex7
Test different error conditions:
- Test 400 Bad Request: Try discount > 90% → Returns validation error with clear message
- Test 422 Business Rule: Apply discount to out-of-stock book → Returns business rule violation
- Test 500 Internal Error: Use percentage = 42 → Returns simulated server error
- Test 501 Not Implemented: Try unimplemented action → Returns "not supported" message
- Test 404 Not Found: Use invalid book ID → Returns "entity not found" error
UI Testing:
These error scenarios help you test how your Fiori app handles different error conditions, improving the
user experience with proper error messages and fallback behaviors.
7.5 Error Handling Best Practices
- Meaningful Error Codes: Use consistent, descriptive error codes that frontend can handle appropriately
- User-Friendly Messages: Provide clear, actionable error messages for end users
- Structured Error Objects: Include additional context like field names, constraints, or suggestions
- Appropriate HTTP Status: Use correct status codes that match the error scenario
- Consistent Format: Maintain consistent error response structure across all actions
Result:
Basic error handling patterns provide a foundation for comprehensive UI testing with realistic error
scenarios.
Next Steps
Exercise 8 will show how to integrate the mockserver with wdi5 for offline end-to-end testing, enabling reliable CI/CD pipelines without backend dependencies.