CAPM Error Handling Made Simple
Share

[[{“value”:”

While developing applications using SAP CAPM, handling errors is an important part of the implementation. For example, a user may try to create an employee without an email address, enter a negative salary, create an employee with an email that already exists, or request an employee ID that is not available.

Instead of allowing these situations to fail without a clear message, CAP provides simple ways to handle business errors and unexpected exceptions.

In this blog, I will demonstrate three practical approaches:

  • req.error() – to report validation errors.
  • req.reject() – to stop processing and return a specific error to the client.
  • try/catch – to handle unexpected exceptions in business logic.

I will use a small Employee application so that each case can be tested from a simple SAPUI5 screen.

What We Will Build

The application contains an Employees entity with ID, name, email and salary. The UI provides three operations:

  • Create Employee
  • Get Employee
  • Calculate Bonus

The backend contains validation and error handling for these operations.

Project Structure

The main files used in this example are:

Pooja_HM_0-1787653108274.png

Step 1 – Create the Database Entity

First, create the Employee entity in the db/schema.cds file. This entity stores the employee information used by the application.

namespace demo.errorhandling;

namespace demo.errorhandling;

entity Employees {
key ID : Integer;
name : String(100);
email : String(100);
salary : Decimal(10,2);
}

Here, ID is the key field. The name and email fields store employee details, and salary stores the employee salary.

Step 2 – Expose the Entity and Define Actions

Next, create service.cds inside the srv folder. The Employees entity is exposed through EmployeeService. Two actions are also defined for retrieving an employee and calculating a bonus.

using demo.errorhandling as db from ‘../db/schema’;
service EmployeeService {
entity Employees as projection on db.Employees;
action getEmployee(ID : Integer) returns String;
action calculateBonus(ID : Integer) returns Decimal;
}

The getEmployee action accepts an employee ID and returns the employee name. The calculateBonus action accepts an employee ID and returns the calculated bonus.

Step 3 – Implement Error Handling in service.js

Now comes the main part of the example. In srv/service.js, we implement the validation and error handling logic.

const cds = require(‘@sap/cds’);
module.exports = class EmployeeService extends cds.ApplicationService {
async init() {
this.before(‘CREATE’, ‘Employees’, async req => {
if (!req.data.email) {
req.error(
400,
‘Email is required’,
’email’
);
}
if (!req.data.name) {
req.error(
400,
‘Employee name is required’,
‘name’
);
}
if (req.data.salary !== undefined && req.data.salary < 0) {
req.error(
400,
‘Salary cannot be negative’,
‘salary’
);
}

if (req.data.email) {
const employee = await SELECT.one
.from(‘demo.errorhandling.Employees’)
.where({
email: req.data.email
});
if (employee) {
req.reject(
409,
‘Employee with this email already exists’,
’email’
);
}
}
});

this.on(‘getEmployee’, async req => {
const { ID } = req.data;
const employee = await SELECT.one
.from(‘demo.errorhandling.Employees’)
.where({
ID: ID
});
if (!employee) {
req.reject(
404,
‘Employee not found’
);
}

return `Employee Name: ${employee.name}`;
});

this.on(‘calculateBonus’, async req => {
const { ID } = req.data;
try {
const employee = await SELECT.one
.from(‘demo.errorhandling.Employees’)
.where({
ID: ID
});
if (!employee) {
req.reject(
404,
‘Employee not found’
);
}

const bonus = Number(employee.salary) * 0.10;
return bonus;
} catch (error) {
console.error(
‘Error while calculating bonus:’,
error
);
req.reject(
500,
‘Unable to calculate employee bonus’
);
}
});

this.on(‘error’, (error, req) => {
console.error(
`CAP Error – Event: ${req.event}`,
error.message
);
});
return super.init();
}
};

Step 4 – Understanding req.error()

The first example uses req.error() for validation. Before an employee is created, the application checks whether the required fields are valid.

For example, if the email is missing:

req.error(
400,
‘Email is required’,
’email’
);

The first parameter is the HTTP status code. Here, 400 means Bad Request. The second parameter is the message shown to the client. The third parameter identifies the affected field.

The same validation is used for employee name and negative salary.

Step 5 – Understanding req.reject()

req.reject() is used when the request should be stopped and a specific error should be returned.

In this example, when the requested employee does not exist, the getEmployee action rejects the request with a 404 error.

if (!employee) {
req.reject(
404,
‘Employee not found’
);
}

The duplicate email check also uses req.reject() with status code 409, because the employee already exists.

if (employee) {
req.reject(
409,
‘Employee with this email already exists’,
’email’
);
}

Step 6 – Exception Handling Using try/catch

Sometimes an error may happen while executing business logic. In such cases, try/catch can be used to catch the exception and return a meaningful error.

try {

const employee = await SELECT.one
.from(‘demo.errorhandling.Employees’)
.where({
ID: ID
});

if (!employee) {
req.reject(
404,
‘Employee not found’
);
}

const bonus = Number(employee.salary) * 0.10;

return bonus;

} catch (error) {

console.error(
‘Error while calculating bonus:’,
error
);

req.reject(
500,
‘Unable to calculate employee bonus’
);
}

In this example, the bonus is calculated as 10% of the employee salary. If an unexpected exception occurs, the catch block logs the original error and returns a controlled 500 error message.

Step 7 – Global Error Handler

The service also contains a global error handler. It is useful when we want to log errors centrally.

this.on(‘error’, (error, req) => {

console.error(
`CAP Error – Event: ${req.event}`,
error.message
);
});

This does not replace the individual validation logic. It is mainly useful for logging and monitoring errors.

Step 8 – Create the SAPUI5 Screen

To demonstrate the backend errors in a practical way, I created a simple SAPUI5 screen. It contains a Create Employee section and an Employee Operations section.

<mvc:View
controllerName=”project1.controller.View1″
xmlns:mvc=”sap.ui.core.mvc”
xmlns=”sap.m”
xmlns:l=”sap.ui.layout”
displayBlock=”true”>
<Page title=”CAP Error Handling Demo”>
<content>

<Panel headerText=”Create Employee” class=”sapUiResponsiveMargin”>
<content>
<l:VerticalLayout width=”100%” class=”sapUiSmallMargin”>
<l:content>
<Label text=”Name” labelFor=”nameInput” />
<Input id=”nameInput” width=”20rem” placeholder=”Employee name” />

<Label text=”Email” labelFor=”emailInput” class=”sapUiTinyMarginTop” />
<Input id=”emailInput” width=”20rem” placeholder=”employee@company.com” />

<Label text=”Salary” labelFor=”salaryInput” class=”sapUiTinyMarginTop” />
<Input id=”salaryInput” width=”20rem” placeholder=”e.g. 50000″ type=”Number” />

<Button text=”Create Employee” type=”Emphasized” press=”.onCreateEmployee” class=”sapUiSmallMarginTop” />
</l:content>
</l:VerticalLayout>
</content>
</Panel>

<Panel headerText=”Employee Operations” class=”sapUiResponsiveMargin”>
<content>
<l:VerticalLayout width=”100%” class=”sapUiSmallMargin”>
<l:content>
<Label text=”Employee ID” labelFor=”opIdInput” />
<Input id=”opIdInput” width=”10rem” placeholder=”e.g. 1″ type=”Number” />

<HBox class=”sapUiSmallMarginTop”>
<Button text=”Get Employee” type=”Emphasized” press=”.onGetEmployee” class=”sapUiTinyMarginEnd” />
<Button text=”Calculate Bonus” type=”Emphasized” press=”.onCalculateBonus” />
</HBox>
</l:content>
</l:VerticalLayout>
</content>
</Panel>

<Panel headerText=”Result” class=”sapUiResponsiveMargin”>
<content>
<MessageStrip id=”resultStrip” text=”Run an operation above to see the result here.” type=”Information” showIcon=”true” class=”sapUiSmallMargin” />
</content>
</Panel>

</content>
</Page>
</mvc:View>

Step 9 – Connect the UI to the CAP Service

The controller uses fetch() to call the CAP OData V4 service. It also reads the error message returned by CAP and displays it using MessageStrip and MessageToast.
This is How I have written in controller.js file

sap.ui.define([
“sap/ui/core/mvc/Controller”,
“sap/m/MessageToast”
], function (Controller, MessageToast) {
“use strict”;

var SERVICE_URL = “/odata/v4/employee”;

return Controller.extend(“project1.controller.View1”, {

_showResult: function (ok, message) {
var oStrip = this.byId(“resultStrip”);
oStrip.setType(ok ? “Success” : “Error”);
oStrip.setText(message);
MessageToast.show(message);
},

_callService: function (method, path, body, onSuccessMessage) {
var that = this;
var options = { method: method, headers: { “Content-Type”: “application/json” } };
if (body !== undefined) { options.body = JSON.stringify(body); }

return fetch(SERVICE_URL + path, options)
.then(function (response) {
return response.json().then(function (data) {
return { ok: response.ok, data: data };
});
})
.then(function (result) {
if (result.ok) {
var msg;
if (typeof onSuccessMessage === “function”) {
msg = onSuccessMessage(result.data);
} else if (typeof result.data.value === “string”) {
msg = result.data.value;
} else if (result.data.value !== undefined) {
msg = String(result.data.value);
} else {
msg = “Request succeeded”;
}
that._showResult(true, msg);
} else {
var errMsg = (result.data.error && result.data.error.message) || “Request failed”;
that._showResult(false, errMsg);
}
})
.catch(function (err) {
that._showResult(false, “Network / unexpected error: ” + err.message);
});
},

onCreateEmployee: function () {
var newId = Math.floor(Date.now() / 1000) % 100000; // simple auto-generated ID
var name = this.byId(“nameInput”).getValue();
var email = this.byId(“emailInput”).getValue();
var salary = this.byId(“salaryInput”).getValue();

this._callService(“POST”, “/Employees”, {
ID: newId,
name: name || undefined,
email: email || undefined,
salary: salary ? Number(salary) : undefined
}, function (data) {
return “Employee created: ” + data.name + ” (ID ” + data.ID + “)”;
});
},

onGetEmployee: function () {
var id = parseInt(this.byId(“opIdInput”).getValue(), 10) || 0;
this._callService(“POST”, “/getEmployee”, { ID: id });
},

onCalculateBonus: function () {
var id = parseInt(this.byId(“opIdInput”).getValue(), 10) || 0;
this._callService(“POST”, “/calculateBonus”, { ID: id }, function (data) {
return “Bonus: ” + data.value;
});
}
});
});

Step 10 – Run the Application

Start the CAP application from the project terminal:

cds watch

After the application starts, open the generated application URL and open the SAPUI5 application.

Note: For this blog, I am demonstrating the error handling through the SAPUI5 screen. Postman is not compulsory for this example.

Here is the Out of My Application

image.png

Step 11 – Test req.error()

To test validation, leave the Email field empty and click Create Employee.

Expected result:

  1. CAP receives the CREATE request.
  2. The before CREATE handler checks the email.
  3. req.error() adds the validation error.
  4. The UI displays the returned error message.
    Pooja_HM_1-1787654378990.png

    Step 12 – Test req.reject() for Duplicate Email

    First create an employee with a valid email. Then try to create another employee using the same email.

    Expected result: the backend checks the existing employee and rejects the second request with HTTP 409.

    Pooja_HM_2-1787654476573.png

     

    Step 13 – Test req.reject() for Employee Not Found

    Enter an employee ID that does not exist and click Get Employee.

    The getEmployee action searches the database. If no employee is found, req.reject(404, ‘Employee not found’) is executed.

    Pooja_HM_3-1787654516710.png

     

    Step 14 – Test a Successful Request

    To show that the service also works for valid requests, enter valid employee details and create the employee.

    Pooja_HM_4-1787654579791.png

     

You can also enter the newly created ID and click Calculate Bonus. For example, if the salary is 34,000, a 10% bonus is 3,400.

Pooja_HM_5-1787654693019.png

req.error() vs req.reject()

Feature

req.error()

req.reject()

Purpose

Report a validation error

Stop the request and reject it

Typical use

Field/business validation

Not found, conflict, unauthorized or other request-level errors

Example

Email is required

Employee not found

Example status

400

404 / 409 / other suitable status

In simple terms: use req.error() when you want to report validation problems during request processing, and use req.reject() when the request cannot continue and should be rejected.

Common Issues While Testing

  • Make sure the CAP server is running before calling the service.
  • Use the correct service path: /odata/v4/employee.
  • Check the action names: getEmployee and calculateBonus.
  • If you are using curl, run the command separately and make sure the URL does not contain terminal prompt text.
  • If you are testing through the UI, check the browser console if the application shows a network error.
  • After changing service.js, restart cds watch if the change is not reflected.

Conclusion

In this blog, we implemented simple error handling in a SAP CAPM application using a practical Employee example.

We covered:

  • req.error() for validation errors.
  • req.reject() for request-level errors such as employee not found and duplicate email.
  • try/catch for handling unexpected exceptions.
  • A global error handler for logging errors.
  • A SAPUI5 screen to test the backend error messages.

Good error handling makes the application easier to use and also makes troubleshooting easier for developers. Instead of showing a generic failure, we can return a clear message that explains what went wrong.

The same approach can be extended to real business scenarios such as customer validation, order processing, duplicate records, authorization checks and other business rules.

I hope this practical example helps you understand error handling in SAP CAPM.
Thank You

“}]] 

  Read More Technology Blog Posts by Members articles 

#abap

By ali

Leave a Reply