cancel
Showing results for 
Search instead for 
Did you mean: 

How to work with CAP CDS > 7 ? .How do i access and modify req.query in custom handlers?

michaelschmid03
Explorer
0 Kudos

When developing CAP CDS for Node.js I regularly had Custom Handlers in which I needed to read some part of the req.query object to make some other backend calls, sometimes I even had to modify the pre-generated queries so that they would properly work on a backend.

Let's take a look on what changed with CDS(here version 7.4.0)

As you can see, req.query.SELECT only contains a from section. Some other params like filter, limit and orderBY are not in this query object, but in Symbol(Original). -Why?



This makes developing with CAP a bit more confusing and more difficult for me.

For Example last week I had accessed a filter with req.req.query.$filter and tried to parse those filter back to CQL, so I could modify and then reattach it to the query parameters. But this doesn't seem like a good Practice

Are there new Best Practices when working with req.query in Custom Handlers using the newer CDS versions? How can I Access req.query.Symbol(Original) in my custom handlers (something like req.query.Symbol(Original) or req.query.['Symbol(Original'] doesnt work)?

Any Guidance or reference to documentation would be massively helpful.

Accepted Solutions (1)

Accepted Solutions (1)

Dinu
Contributor

The view in the debugger is misleading you. You can access all the information you need as properties. Try the following and you will see that information is available.

let {from,columns,where,orderBy,limit} = req.query.SELECT
EkanshCapgemini
Active Contributor
0 Kudos

Ohh.. yes. You are right. Somehow the debugger doesn't show these. I am surprised.

michaelschmid03
Explorer
0 Kudos

you're totally right. i've never noticed this. Why would the debugger even hide the fields even though they are still there

i've actually wrote this abomination of code to solve it temporarily but this will now go away of my production code hopefully forever

  /**
   * Because CDS annoyed me with accessing filters in a normal way
   * @Param{String} sFilterString
   * @returns {Object} aParams,all filters indexed by Property
   */
  parseFilterString(sFilterString) {
    if (!sFilterString) return;
    const sCleanedString = sFilterString.replace(/['()]+|\b(?:and|or)\b/g, "");
    let aStringElements = sCleanedString.split(/\s+/);
    let aParams = {};
    while (aStringElements.length > 0) {
      const [paramName, operator, value, ...rest] = aStringElements;
      aParams[paramName] = aParams[paramName] || {};
      aParams[paramName][operator] = value;
      aStringElements = rest;
    }
    return aParams;
  }
michaelschmid03
Explorer
0 Kudos

-

michaelschmid03
Explorer
0 Kudos

-

Answers (2)

Answers (2)

Subramaniyam
Explorer
0 Kudos

Hi @michaelschmid03  , 

 I have come across a similar kind of situation where in additional filters were required when calling S4 odata service.

For example let say we want to filter certain dataset on CompanyCode="XYZ" , you could manipulate the req.query object in this fashion 

srv.on('READ','Myentity',async req=>{
      const someRMtservice = await cds.connect.to('SomeRemoteService')

    if(req.query.SELECT !== undefined){
      const condtionLiteral = `CompanyCode='XYZ'`

     //instantiate the cxn parser object
      const parser= cds.parse;
      // parse cxn : resultant =>   {xpr:[ {ref:['CompanyCode']}, '=', {val:'XYZ'} ]}
      const cxnObject = parser.expr(condtionLiteral);
      const cxnArray = [...cxnObject];
      req.query.SELECT.where = cxnArray;
    }

    const data = await someRMtservice.run(req.query);
    return data 
})

Please also have a look at this documentation of CXN - CXN-Expression Notation  .

Let me know if this works for you.

Thank you 

Regards

Subramaniyam N 

 

Subramaniyam
Explorer
0 Kudos

Hi @michaelschmid03 ,

 

There is a correction at line 11

Please find the updated code: 

srv.on('READ','Myentity',async req=>{
      const someRMtservice = await cds.connect.to('SomeRemoteService')

    if(req.query.SELECT !== undefined){
      const condtionLiteral = `CompanyCode='XYZ'`

     //instantiate the cxn parser object
      const parser= cds.parse;
      // parse cxn : resultant =>   {xpr:[ {ref:['CompanyCode']}, '=', {val:'XYZ'} ]}
      const cxnObject = parser.expr(condtionLiteral);
      const cxnArray = [...cxnObject.xpr];
      req.query.SELECT.where = cxnArray;
    }

    const data = await someRMtservice.run(req.query);
    return data 
})

 

michaelschmid03
Explorer
0 Kudos

HI @Subramaniyam , as you can see theres already an accepted Solution to this Issue. And your Answer doesnt solve this since we were talking about Reading and not Modifying Filters.

Im also totally aware of how to modify Querys. But if we talk about this i Think, that your approach is actually less Readable and more complex than it has to be. Since parsing is handled automatically before query Excecution, you should be able to just push your own Filterin a more readble object literal or string format to the .where of said req.query object

Best Regards,
Michael

david_kunz2
Advisor
Advisor
0 Kudos

Hi michaelschmid03 ,

You must not access Symbol(original), this is not public API.

Your handler must only take care of req.query, as is.

Note: Some properties might be part of the prototype chain.

Best regards,
David

michaelschmid03
Explorer
0 Kudos

okay, then but how can i edit and read the Params of a query like .limit .filter and orderBy of a query, if those aren't inside the req.query object but only in Symbol(original)?

david_kunz2
Advisor
Advisor
0 Kudos

Your handler must not take into account Symbol(original). It must only take into account req.query. If there's some property missing, your handler must not take that property into account.

michaelschmid03
Explorer
0 Kudos

Sorry for bothering you again david.kunz2 , I realize that this would work fine in the case of odata services, but in some cases I also have rest services or odata services that aren't obeying all typical odata conventions, So in these cases that wouldn't be an option right? I failed to mention this in my initial question.

david_kunz2
Advisor
Advisor
0 Kudos

Hi Michael, no bother at all 🙂

req.query is normalized across different incoming protocols (OData, REST, GraphQL, ...).

EkanshCapgemini
Active Contributor
0 Kudos

Hi david.kunz2,

I have the exact same question. Could you please explain what you meant by `If there's some property missing, your handler must not take that property into account.` ?

How do I access the parsed filters etc.? Why does CAP assumes that my business logic doesn't need the passed filters?

Br, Ekansh

david_kunz2
Advisor
Advisor
0 Kudos

Hi ekansh005 ,

You have access to the parsed filters in req.query.SELECT.where and req.query.SELECT.from.ref, depending how the service is called.

Best regards,

David