Application Development Discussions
Join the discussions or start your own on all things application development, including tools and APIs, programming models, and keeping your skills sharp.
cancel
Showing results for 
Search instead for 
Did you mean: 

Task 11 - Using implicit parameters with a bound function (July Developer Challenge - "Reverse APIs"

qmacro
Developer Advocate
Developer Advocate
3,139

This is the final task in the July Developer Challenge - "Reverse APIs". Well done for making it this far! 🎉

Background

In the tasks in this challenge so far you've encountered, amongst other things, actions and functions. But all of those actions and functions you've had to define and write implementations for ... have been unbound, i.e. not bound to a specific instance of an entity. The Capire section Custom Actions and Functions is relevant here. Think of these types of actions and functions as being at the service level (vaguely like static methods in OO).

With that section there's a subsection Bound Actions and Functions which describe actions and functions that can be defined to be in the context of an entity (to continue the vague OO analogy, these are like instance methods).

In this task you'll define a bound function, and (will be encouraged to) use destructuring to determine the implicit binding parameter (this binding parameter can also be modelled explicitly but we won't be doing that as it's far less common).

Defining a bound function

Check the Capire docs to learn how to define a bound function, in CDL. It involves declaring an actions block as a continuation of the entity definition to which you want your function bound. Note that despite the block having the name actions, it is for containing definitions of both bound actions and functions.

Implementing a bound function

Implementing a bound action or function is pretty much the same as implementing an unbound one. The only difference really is that you need to get the value of the binding parameter, i.e. the key that the infrastructure gives your handler to point to the specific instance of the entity in the context of which the bound action or function is being called.

Here's the difference, using the Northbreeze service, served via the OData adapter, at the default path. First, let's remind ourselves of how an unbound function is called, which is like this - note the absence of any entity name or key:

/odata/v4/northbreeze/unboundFunction()

Now, a bound function is called like this - note the function name follows the path of a specific entity:

/odata/v4/northbreeze/Products(42)/boundFunction()

or (using the OData V4 key-as-segment approach) like this:

/odata/v4/northbreeze/Products/42/boundFunction()

The value 42 is the value of the binding parameter that you need to implement such a bound function. Where is that? It's available in the incoming request, specifically in the params property.

In order to retrieve the value, you'll need to grab it from the request object. How you do that is of course up to you, but I'd encourage you to try it in the "normal" way of a dotted path notation from req, for example:

const ID = req.params[0].ProductID

but also using a destructuring assignment in the actual function signature, i.e.

async (<SOME-DESTRUCTURING-ASSIGNMENT-HERE>) => { ... }

Remember also that you'll probably want to re-check the details of the srv.on request, as you'll want to include the Products entity name in that incantation in the optional entity? position:

function srv.on (event, entity?, handler: (
  req  : cds.Request,
  next : function
))

The requirements

Here are the specific requirements for this task.

Define a bound function called stockValue on the Products entity in your Northbreeze service. This should return an integer value being the value of the bound product's stock, which should be calculated as the product's UnitPrice multiplied by its UnitsInStock. For example, for product Chai:

{
  "@odata.context": "$metadata#Products/$entity",
  "ProductID": 1,
  "ProductName": "Chai",
  "QuantityPerUnit": "10 boxes x 20 bags",
  "UnitPrice": 18,
  "Category_CategoryID": 1,
  "Supplier_SupplierID": 1,
  "UnitsInStock": 39,
  "UnitsOnOrder": 0,
  "ReorderLevel": 10,
  "Discontinued": false
}

the stock value is 702 (18 x 39).

Submitting to the TESTER

Now you're ready to submit your CANDIDATE service, with this new API endpoint, to the TESTER!

The payload

The task identifier you need to supply in the payload of your submission is: northbreeze-stockValue.

You'll have already done this sort of thing previously so just head back there for the more detailed instructions if you need them, or to the the section titled "The Tester service, and making a test request" in the main challenge blog post.

You'll need to submit a JSON payload like this:

{
  "communityid": "<your-community-id>",
  "serviceurl": "<the-URL-of-your-service>",
  "task": "northbreeze-stockValue"
}

And, just as with the previous (and all further tasks):

  • the value for the communityid property should be your ID on this SAP Community platform (e.g. mine is "qmacro")

  • the value for the serviceurl property should be the absolute URL (i.e. including the scheme), of your CANDIDATE service which contains the API endpoint (see ℹ️ A note on URLs and services).

That's it!

Logging of test results

Remember that you can check on your progress, and the progress of your fellow participants - all requests are logged and are available in an entity set served by the TESTER service. The entity set URL is https://developer-challenge-2024-07.cfapps.eu10.hana.ondemand.com/tester/Testlog and being an OData V4 entity set, all the normal OData system query options are available to you for digging into that information.

If you have any questions or comments, leave them below!

25 REPLIES 25

HPSeitz
Active Participant
3,084

passed.png

really cool challenge, thx DJ

AndrewBarnard
Contributor
3,049

Ok Done ( in the sense that the TESTER service says pass ).

johna69
Product and Topic Expert
Product and Topic Expert
2,986

Thanks DJ, was a fun late night playing catchup. Great learning and now have the awesome ngrok in my toolbox. 

YogSSohanee
Participant
2,967

My submission for task 11:

YogSSohanee_0-1722359320289.png

OData call:

YogSSohanee_2-1722359485826.png

 

 

MioYasutake
Active Contributor
2,913

My submission for task 11.

MioYasutake_0-1722369802563.png

 

Liyon_SV
Explorer
2,885

Done 😀

Liyon_SV_0-1722386282770.png

 

Cmdd
Participant
2,824

Task 11 submission 

Cmdd_0-1722413772483.png

 

sudarshan_b
Participant
2,777

Finally got it working with the destructuring assignment, the MDN documentation helped 🙂

Here's my submission - 

sudarshan_b_0-1722416509243.png

Thank you.

 

spassaro
Participant
2,774

.on (..., async({ params: [ { ProductID } ] }) => (...)

aren't you a Beauty Javascript? By the way, i had to rely on db.entities to pull off Products because my  northbreezeService, which extends the cds.ApplicationService, raises an error when I try to declare this.on(..., Product, async(req) => ). Not sure why is that, but I'll dive into it!

 

spassaro_0-1722416841826.png

 

qmacro
Developer Advocate
Developer Advocate
0 Kudos
2,371

Indeed! Dive in and have fun, that's the idea! 👍

geek
Participant

2,586

geek_0-1722442096866.png

Some rework, as I find that some of these requirements are a bit too ambiguous. Still not sure that am using destructuring assignment or whether there's more to the "entity?" parameter.

qmacro
Developer Advocate
Developer Advocate
0 Kudos
2,373

I'm not going to be able to comment on whether you're using destructuring assignment if you don't show me the code ... 🙂 

Which bits are ambiguous? Your statement itself is a little ... ambiguous 😉

tobiasz_h
Active Participant
2,632

Hello,
My submission:

tobiasz_h_0-1722434065452.png

I had problems with including the Products entity name in srv.on method and I didn't use this option:

function srv.on (event, entity?, handler: (
  req  : cds.Request,
  next : function
))

 

MatLakaemper
Participant
2,615

Here my Submission.

MatLakaemper_0-1722435698931.png

 

MatLakaemper_1-1722435721572.png

 

 

 

gphadnis2000
Participant
2,559

Finally all task submitted for challenge. My submission for Task11.

gphadnis2000_0-1722443505237.png

 

qmacro
Developer Advocate
Developer Advocate
0 Kudos
2,373

Please don't forget task 12, @gphadnis2000 ! 🙂

0 Kudos
2,245

Yes i wont forget and very challenging task for July 🙂

Alpesa1990
Participant
2,550

My submission for task 11

Alpesa1990_0-1722443772208.png

 

M-K
Participant
2,457

Here's is my submission:

MK_0-1722462631997.png

 

vineelaallamnen
Explorer
2,157

Task 11 - Action call is working 

vineelaallamnen_0-1722552652599.png

 

Service is not able to reach

vineelaallamnen_1-1722552700169.png

 

0 Kudos
2,105

Might be worth checking your service URL

0 Kudos
2,023

Hi DJ

Service seems fine 

vineelaallamnen_0-1722608887774.png

 

Still test service seems to fail for me. It worked also for other unbound functions in other tasks 

vineelaallamnen_1-1722608951103.png

 

vineelaallamnen_2-1722609016085.png

 

 

mxmw
Explorer
0 Kudos
2,083

Final assignement finished 🎉

mxmw_0-1722604941950.png

Thanks for the Challenges!

Nidhi
Product and Topic Expert
Product and Topic Expert
0 Kudos
1,402

Hi @qmacro ,

I am able to test the bound action locally.

Nidhi_0-1722877459956.png

However, when I push the app and test it, I am getting below error.

Nidhi_1-1722877526467.png

I didn't faced this issue before. I would appreciate any hint on how to fix this?