Application Development Blog Posts
Learn and share on deeper, cross technology development topics such as integration and connectivity, automation, cloud extensibility, developing at scale, and security.
cancel
Showing results for 
Search instead for 
Did you mean: 
qmacro
Developer Advocate
Developer Advocate
10,522

TL;DR This is the main blog post for the SAP Developer Challenge in July and contains a general overview, hints and tips, and the list of tasks that you need to carry out during this challenge. If this is your first time reading this post, jump down to the "Introduction" section and start there. Otherwise, find the list of tasks you need to complete directly below, in the "Tasks" section.

Tasks

There are 12 tasks in total (plus a final bonus "feedback" task). The first (Task 0) is just for you to get things set up for the subsequent tasks. Each task listed here is just a one line summary, and links to a separate task-specific thread in the Application Development Discussions area of this SAP Community platform. Each thread title will follow this pattern:

Task <task number> - <Task short description> (July Developer Challenge - "Reverse APIs")

🔔This task list will be updated throughout the month, check back regularly to see what's next - and if there's a task that's hyperlinked, then you can follow that hyperlink to start the task!

0 - Server and service provisioning: Get comfortable with spinning up a CAP server and basic service and provisioning a route to it in the cloud.

1 - Your first service and first endpoint: Nice and simple to start off with, an unbound function that takes no parameters and should return a specific value.

2 - Capire's "Hello World": An unbound function with a single parameter, that should return a value that combines static text with the value of the argument passed to that parameter.

3 - Basic sum function: The final of the basic unbound function style API endpoints in the context of an OData V4 service, before moving on to a different protocol.

4 - Plain "REST" endpoint: Moving away from the default OData V4 protocol, this is an API endpoint you must define within a new service and have served via the "REST" protocol.

5 - A "REST" service document: Continuing to explore the difference between CAP's OData and "REST" protocol adapters.

6 - An API endpoint with a payload required: Another endpoint in the plain "REST" service, but a little different in its definition, implementation, and how it's called.

7 - Using CQL in an unbound function implementation: In your implementation for a brand new service similar to Northwind, you'll have to use some CQL to respond to a request to an unbound function.

8 - Responding to an OData query with navigation: Learning how useful out-of-the-box supported standard OData mechanisms can be.

9 - Using CQL in an unbound action: Similar to Task 8 but with a little bit of added spice in the form of some JavaScript calculations.

10 - The power of CDL with as-select: Extending the service in the CDS model, with no extra implementation required.

11 - Using implicit parameters with a bound function: Understanding implicit vs explicit parameters, and destructuring to get the value, with bound actions and (in this case) functions.

Bonus (and important) task:

12 - Give us feedback about this challenge: This is an opportunity for you to tell us what you liked, what you didn't like, and what you learned from this month's challenge.

Introduction

This SAP Developer Challenge for the month of July echoes last year's August challenge on APIs, but turns it around. The August challenge last year had you making API calls to different endpoints on various services. This month's challenge will have you setting up and running various services, each with different endpoints. 

The idea is for us all to go on a small journey of discovery and experience the joy of setting up APIs with the power of CAP - defining them in CDS models (in Core Definition Language, CDL) and implementing them, where required* in either Node.js or Java. If you want help along the way, you'll get it in the form of hints in the Node.js flavour of CAP, but if you want, you're welcome to use Java too of course. After all, the API contract is what's important, right?

Over the month you'll set up 10 API endpoints over 3 different services.

* remember that CAP has a rich set of generic providers that means for much of the standard CRUD+Q request landscape you don't have to implement anything yourself.

Challenge overview

How will the challenge work? What happens when you set up a service with some API endpoints? How will we know when a specific endpoint has been set up and served successfully? Well, here's a small diagram that will help to answer that, and some terminology.

steps.gif

The mechanism that we will be using to "run" the challenge is the TESTER. It's actually just a very simple CAP service that has a single endpoint `testService` that you will need to call once you have a service and endpoint ready.

The service you set up is known as the CANDIDATE. Each CANDIDATE service will have one or more endpoints.

The TESTREQUEST is when you have a service and endpoint ready to be tested, and you make a request for it to be tested, supplying three pieces of information.

The TESTRESULT is the result of such a TESTREQUEST, and will be either PASS or FAIL.

As well as returning PASS or FAIL to the TESTREQUEST call, the results of the test will be logged and retrievable as an OData V4 entity set (details on this will follow later).

The services

The three services you'll set up over this challenge are deliberately simple, and are intended to help you discover various aspects of service definition and implementation. You will define two of the services as OData V4 protocol based (this is the default in CAP anyway), and one as plain "REST" protocol based.

Over these three services you'll define multiple endpoints, of different "types", including:

  • unbound function with no parameters
  • unbound function with parameters
  • unbound action with data
  • bound action
  • projection with the 'as-select' variant
  • various query operations

To give you a couple of examples, in the first service you'll define, called `basic`, you must create an endpoint `sum` defined as an unbound function that takes two parameters `a` and `b` and returns the sum of the values of those two parameters. In another service you'll define, called `northbreeze`, which you'll have to seed with data too, you must create an endpoint `stockValue` as a bound action that takes no parameters* and returns the total stock value for a product.

* remember that a bound action or function has an implicit "parameter" in terms of the specific entity to which it is bound at call time.

Making your service available to test

The question right now on your mind is likely to be "How does step 4 (Endpoint is tested by calling it) work?". It's easy to set up a CAP service locally. But how can a service running in the cloud connect to and test your service?

Well, you have many options, and what you end up doing is down to you - your personal preferences, what else you want to learn or practise along the way, and how "temporary" you want to make your service availability.

Simple deployment to BTP

While there is some data that the third of the three services in this challenge will need to have and to serve, it can be served via the SQLite in-memory mechanism built in to the CAP server, and doesn't need a persistence layer, i.e. doesn't need any sort of backing service. All three of the CAP-based services you will need to create are simple enough to be deployed as-is, in other words, on their own.

In fact, it is perfectly possible for you to serve all three services in a single CAP server instance, so if you choose to, you can just have a single CAP project, with a single CAP server (started with `cds serve` for example) and have that server provide all three services.

Given that, it's actually rather straightforward to deploy a test CAP project to BTP, specifically to a Cloud Foundry runtime. Everyone has access to a trial account on BTP at no cost (and no credit card required), and a Cloud Foundry runtime instance is set up automatically when you create a trial account (or you can provision one after the fact if you don't have one).

Assuming you have a Cloud Foundry runtime instance in a trial account, and have logged in with the cf CLI, here's a (deliberately short) one-liner that:

  • creates a simple CAP project with some test data
  • adds cds configuration to ensure that SQLite in-memory persistence is used and that no real authentication is required*
  • adds the NPM sqlite3 package as a dependency
  • pushes the entire project to Cloud Foundry and starts the server running

 

cds init --add tiny-sample qmacro-simplest-deployment \
&& cd $_ \
&& jq '.+{cds:{features:{in_memory_db:true},requires:{auth:"mocked",db:{kind:"sqlite",credentials:{database:":memory:"}}}}}' package.json > tempfile \
&& mv tempfile package.json \
&& npm add sqlite3 \
&& cf push "$(basename "$PWD")"

 

(Yes, for those fellow shell nerds out there, I am using `"$(basename "$PWD")"` on the last line to avoid repeating the "qmacro-simplest-deployment" name and keep things DRY).

*if you haven't got jq, first of all, why not? But seriously, just use the terminal in a "Full Stack Cloud Application" Dev Space in SAP Business Application Studio, the default shell is Bash and it has lots of useful tools including all of those used in this invocation (cds, jq, npm and cf). It's a very useful environment.

Once the server is running in Cloud Foundry, you can check the URL like this:

 

cf app qmacro-simplest-deployment

 

and you should see something like this:

 

Showing health and status for app qmacro-simplest-deployment in org dj-adams-42-ajjk4v42-org / space dev as dj.adams@sap.com...

name:              qmacro-simplest-deployment
requested state:   started
routes:            qmacro-simplest-deployment.cfapps.eu10.hana.ondemand.com
last uploaded:     Wed 03 Jul 07:14:25 UTC 2024
stack:             cflinuxfs4
buildpacks:
        name               version   detect output   buildpack name
        nodejs_buildpack   1.8.24    nodejs          nodejs

type:           web
sidecars:
instances:      1/1
memory usage:   1024M
     state     since                  cpu    memory        disk           logging             details
#0   running   2024-07-03T07:14:37Z   1.3%   92.5M of 1G   195.2M of 1G   0B/s of unlimited

 

The URL that the CAP server is publicly available on is shown in the "routes" line, here it is:

 

https://qmacro-simplest-deployment.cfapps.eu10.hana.ondemand.com

 

Local deployment plus ngrok tunnel

If you want to keep your CAP development local, you can do, of course. This is great especially if you want to use all the goodness of the short, tight development cycle that `cds watch` affords. But you need some way of provisioning a route to your locally running CAP server so that the TESTER can reach it. This is where a tool like ngrok comes in. It's a "secure unified ingress platform" and has many features and functions, but, in its basic form, it's a way of setting up a secure reverse proxy tunnel to a port on your local machine. This sort of facility is free, and I use it often.

Here's the "equivalent" of the above invocation if you want to take this approach:

 

cds init --add tiny-sample qmacro-local-execution \
&& cd $_ \
&& cds watch

 

The `cds watch` command should start up the CAP server on the default port of 4004.

Then, in a separate terminal window, invoke ngrok* like this:

 

ngrok http 4004

 

and you should see a reverse proxy endpoint set up, and a monitor showing something like this:

 

ngrok                                                                                                                                                                                                                                                       (Ctrl+C to quit)

Try our new Traffic Inspector: https://ngrok.com/r/ti

Session Status                online
Account                       DJ Adams (Plan: Free)
Version                       3.12.0
Region                        Europe (eu)
Latency                       57ms
Web Interface                 http://127.0.0.1:4040
Forwarding                    https://421f-85-255-232-142.ngrok-free.app -> http://localhost:4004

Connections                   ttl     opn     rt1     rt5     p50     p90
                              1       0       0.02    0.00    6.58    6.58

HTTP Requests
-------------

07:55:58.878 UTC GET /odata/v4/catalog/Books    200 OK
07:55:57.531 UTC GET /favicon.ico               200 OK
07:55:57.363 UTC GET /                          200 OK

 

The URL that the CAP server is publicly available on in this case is shown in the "Forwarding" line, here it is:

 

https://421f-85-255-232-142.ngrok-free.app

 

ℹ️A note on URLs and services

There's something relating to URLs that is important to remember that in all cases, including both these two specific approaches (CF-on-BTP and ngrok-based) to running and exposing routes to CAP server based services.

There's a difference between the URL of the CAP server generally, and a service (served by that CAP server) in particular.

Taking the CAP server URLs we saw from both these approaches, we have:

Accessing either of these URLs (they're not active at this time) would give you the classic CAP server landing page:

qmacro_0-1719994877339.png

The CAP server that is presenting the landing page at these URLs is not only serving that landing page (at the root path, i.e. at `/`, after the fully qualified domain name e.g. `qmacro-simplest-deployment.cfapps.eu10.hana.ondemand.com` or `421f-85-255-232-142.ngrok-free.app`), let's call that the "root URL", but also a single service, here at `/odata/v4/catalog` which of course would return the "service document" for that specific service.

This distinction is important to remember when making test requests throughout the course of this month's tasks.

The Tester service, and making a test request

Once you have created a service, and have an endpoint in that service that corresponds to a task in this challenge, you are ready to have that endpoint tested to see if you've fulfilled the task criteria and created an endpoint that responds appropriately.

This is step 3 (Request a test of that service's endpoint) in the diagram shown earlier.

The "root URL" of the CAP server representing the TESTER side of the diagram is:

https://developer-challenge-2024-07.cfapps.eu10.hana.ondemand.com/

The URL of the tester service itself is:

https://developer-challenge-2024-07.cfapps.eu10.hana.ondemand.com/tester

and as you can see from the response for that URL, it's an OData service (you get the service document which includes some `@odata` based properties), with a single entity set "Testlog" which we can ignore for now.

The service metadata document at:

https://developer-challenge-2024-07.cfapps.eu10.hana.ondemand.com/tester/$metadata

shows us that there's an `ActionImport` called `testServer`, defined as an unbound action with three parameters:

Screenshot 2024-07-03 at 10.24.37.png 

When you want to request that the TESTER makes a test to one of your service endpoints, you must call this action import and supply values for each of the three parameters:

  • communityid
  • serviceurl
  • task

Being an action, the call must be made using the HTTP POST method. Provide the values in a JSON object in the body of the HTTP request. Here's an example of such a payload for a task that will come later this month in this challenge, which is called "northbreeze-selectproduct", based on a CANDIDATE server available via the earlier ngrok-based provisioning option, at a CAP server base URL of https://421f-85-255-232-142.ngrok-free.app:

 

{
  "communityid": "qmacro",
  "serviceurl": "https://421f-85-255-232-142.ngrok-free.app/odata/v4/northbreeze",
  "task": "northbreeze-selectproduct"
}

 

Note the "communityid" value is your name on this SAP Community platform, for example mine is "qmacro". My numeric SAP Community user ID is 53 but the SAP Community ID we're using here is exactly the same as the one we used for the Developer Challenge on APIs last year.

Note that the value for the `serviceurl` property is a combination of the CAP server base URL plus the relative path of the service itself i.e. `/odata/v4/northbreeze`. 

This needs to be sent, in the body of an HTTP POST request, to the following URL:

https://developer-challenge-2024-07.cfapps.eu10.hana.ondemand.com/tester/testServer 

Don't forget to include a Content-Type header specifying the media type `application/json`:

 

Content-Type: application/json

 

Here's a (reduced) verbose output from a `curl` request that makes this exact request with the payload shown above:

 

./request-test qmacro /odata/v4/northbreeze northbreeze-selectproduct
* Connected to developer-challenge-2024-07.cfapps.eu10.hana.ondemand.com (3.124.222.77) port 443 (#0)
> POST /tester/testServer HTTP/2
> Host: developer-challenge-2024-07.cfapps.eu10.hana.ondemand.com
> user-agent: curl/7.88.1
> accept: */*
> content-type: application/json
> content-length: 138
>
< HTTP/2 200
< content-type: application/json;odata.metadata=minimal
< date: Wed, 03 Jul 2024 09:40:12 GMT
< odata-version: 4.0
< x-powered-by: Express
< content-length: 56
<
{"@odata.context":"$metadata#Edm.String","value":"PASS"}

 

(Let me know in the comments if you'd like to see the `request-test` script here).

What's happened between the request and the response here is essentially what's shown in step 4 (Endpoint is tested by calling it) in the diagram, and the output returned:

 

{"@odata.context":"$metadata#Edm.String","value":"PASS"}

 

is the TESTER's response, here showing that the endpoint passed the task test (if it hadn't, the value would be "FAIL").


The idea for this challenge, and the idea for last year's API challenge to which this is a reflection, both came from my lovely son Joseph. Everything that you like about these challenges are down to him. Anything that you don't like, anything that goes wrong, is down to me and my inability to execute properly.


Sorry about the gratuitous whitespace before and after code sections - they are added automatically and I cannot get rid of them.

17 Comments
ajmaradiaga
Developer Advocate
Developer Advocate

Looking forward to this dev challenge!

Vitaliy-R
Developer Advocate
Developer Advocate

@ajmaradiaga do not forget to look backward first and complete the June developer challenge 🤓

mwn
Participant

Nice challenge!

For those of us who want to use the local deployment option, where do we find ngrok? I have the CAP extensions in my workspace.

 

Thanks

 

qmacro
Developer Advocate
Developer Advocate
0 Kudos

Thanks @mwn ! You can find ngrok via the link in the text above (in the Local deployment plus ngrok tunnel section). Good luck and if you have any questions using ngrok or generally exposing a service - go ahead and jump to Task 0 - Server and service provisioning and ask there, that thread is designed to discuss all things like this. Cheers!

ajmaradiaga
Developer Advocate
Developer Advocate

@Vitaliy-RI actually need to go back all the way to May... as I also need to complete @noravonthenen AI challenge. I honestly don't know where May and June went... so many things happening.

YogSSohanee
Participant

Hello,

Has anyone faced this issue with routes:

Routes cannot be mapped to destinations in different spaces

YogSSohanee_0-1720375265188.png

I tried following this approach, but did not help. I checked in the BTP gui as well for any possible routes which i can delete, but could not find any.

YogSSohanee_1-1720375325397.png

Any help would be really appreciated! Thanks.

-------------------------------------UPDATE------------------------------------------------------------------------

I tried this with another trial account with my personal email ID and it worked fine. I was able to create the app, push it to CF and then do a call with testServer as well. 

 

 

qmacro
Developer Advocate
Developer Advocate

Hi @YogSSohanee - I'm glad you got this resolved (in a different trial account). The problem you encountered at first ("Routes cannot be mapped to destinations in different spaces") is likely to have been a result of an app with the same name (YogSSohanee-simplest-deployment) already existing, with a route, elsewhere, on that Cloud Foundry instance. 

AndrewBarnard
Contributor

Hi @qmacro Yes - I would like to see your request-test script in the blog post. 

qmacro
Developer Advocate
Developer Advocate
0 Kudos

Hey @AndrewBarnard thanks for asking / confirming. I was going to share just the script, but it's better in context. Before I share the wider context, I need to do some pruning so as not to give away anything that's coming up yet. Bear with me, please (and hassle me if I don't share it in the next day or two). Thanks! DJ

qmacro
Developer Advocate
Developer Advocate

Thanks for joining today's live stream @AndrewBarnard , here's the request-test script, in a gist because I can't seem to be able to paste a pre formatted monospaced script here 😞 https://gist.github.com/qmacro/726765c8cbe18d023487e45a3264bad0 

BH91976
Explorer
hcordeiro
Explorer
0 Kudos

.

nsathya_infy
Explorer

@qmacro Hello DJ,

Is there a way we could install ngrok with BAS terminal?

 

Thanks a lot for the guidance all around. With Gratitudes, Sathya

qmacro
Developer Advocate
Developer Advocate

Hi there @nsathya_infy 

Indeed you can. There's just a regular old Debian powered x86_64 architecture Linux box (I am fond of saying "the Cloud is just a load of Linux machines" :-)). But one thing you need to know is that HTTP/S access to the outside world is via a proxy, managed by the BAS infrastructure. And while ngrok can work with proxies like this, it's an enterprise-grade feature that is not free. And I have to also say that running ngrok in a Dev Space is probably not allowed, at least not for commercial purposes.

Here's a suggestion, though - if you needed a remote/virtual work space to do these tasks, then you could try GitHub Codespaces. Like BAS Dev Spaces, they're also based on VS Code (Code OSS to be more precise) and you'll have almost exactly the same IDE experience, including a terminal. 

Here's a screenshot of everything you'd need to do - downloading, installing, configuring and starting ngrok, for a locally (in the Codespace) running CAP service. If you clone the northbreeze GitHub repo then you can start a codespace via the green Code button (select the down-arrow for options) and go from there. Good luck! 

Screenshot 2024-07-26 at 14.12.43.png

 

nsathya_infy
Explorer

Thanks, DJ. That helps I will give code spaces a try.🙂

JimSpath
Active Contributor

Interesting that none of the July answers I saw posted had code in text boxes; all I can see are screenshots. We should encourage the former, for readability where feasible. 

Edit: I took a random entry screenshot, ran it though an online image-to-text converter, and get this result using the code sample style here (as HTML/XML):

@northbreeze_url=https://m-k-simplest-deployment.cfapps.us10-001.hana.ondemand.com/odata/v4/northbreeze
### Key-as-Segment
Send Request
GET {{northbreeze_url}}/Suppliers/7
### Category-Name
Send Request
GET {{northbreeze_url}}/Suppliers/7/Products/70/Category/CategoryName
### Category-Name scalar
Send Request
GET {{northbreeze_url}}/Suppliers/7/Products/70/Category/CategoryName/$value
### Mixed with parentheses-style
Send Request
GET {{northbreeze_url}}/Suppliers/7/Products(70)/Category/CategoryName/$value

 More readable and accessible with minimal effort. The more Community posts that leverage our platform tools the better.

qmacro
Developer Advocate
Developer Advocate
0 Kudos

I fully agree! Unfortunately I think it may be just that there's too much friction (as you have amply demonstrated in your ninja edit :-)) to be able to do that comfortably and effectively. I've already provided feedback internally on this of course, as you'd expect / hope / guess. Fingers crossed! 

Labels in this area