Skip to Content
Jan 24, 2020 at 10:00 AM

CAP Custom event handlers & OData queries



I am currently working on an application using CAP & Node.js. The application is basically a service that aggregates data from existing standard SAP APIs, and a Fiori Elements front-end (List Report & Object Page).

To be able to aggregate the data of the APIs, I use a custom service implementation in Javascript, with the event handlers (before, on, after).

My problem is that I am not able to re-implement the OData V4 $count query (in the custom handlers), that is necessary to have the Fiori Elements list report to work. Apparently the custom handlers "overwrite" the standard $count handler ? Therefore, the List Report issues the following request:

READ Entity {
  '$count': 'true',
  '$select': '...',
  '$skip': '0',
  '$top': '30'

But gets the following answer:

  "@odata.context": "$metadata#Entity",
  "@odata.metadataEtag": "...",
  "@odata.count": 0,
  "value": [
    { ... }, { ... }, ...

Since the @odata.count value is 0, the List Report does not display any data. I did not find any way to set this value in the custom handlers, since it seems that I only have access to the "value" array.

So my question is: Is there a way to set a custom value for the results array and still have the standard OData handlers work ?

My question is specifically for the $count query, but I would also like to avoid re-coding the $filter and $sort logic if possible.

Here is a sample of my current implementation:

srv.on('READ', 'Entity', async (req) => {
	const queryOptions = req._.odataReq.getQueryOptions() || {};

	const [data1, data2, data3] = await Promise.all(['Entity1')),'Entity2')),'Entity3')),
	const elements = [...data1, ...data2, ...data3]
		.map((el) => ({ Prop1: el.Prop1, Prop2: el.Prop2, Prop3: el.Prop3 }));

	const reqData =;
	if (reqData && reqData.Prop1 && reqData.Prop3) {
		const element = elements.find((el) => el.Prop1 === reqData.Prop1 && el.Prop3 === reqData.Prop3);
		return element;
	const top = queryOptions.$top || flows.length;
	const skip = queryOptions.$skip || 0;
	return elements.slice(skip, (skip + top <= elements.length ? skip + top : elements.length));

srv.after('READ', 'Entity', async (results, req) => {
	const queryOptions = req._.odataReq.getQueryOptions();
	if (queryOptions && queryOptions.$expand) {
		if (!Object.keys( {
			req.reject(501, 'Not implemented');
		} else if (results.length) {
			const el = results[0];
			const items = await'EntityItems').where({ Entity_Prop1: el.Prop1, Entity_Prop3: el.Prop3 }));
			el.Items = items;

srv.on('READ', ['Entity1', 'Entity2', 'Entity3'], async (req) => {
	// Handling with request to external API

Thanks for your help,