Task 8 – Responding to an OData query with navigation (July Developer Challenge – “Reverse APIs”)

This is a task in the July Developer Challenge – “Reverse APIs”.

This time, a simple one that should take you no time! After the previous task where you created a brand new Northbreeze service, complete with data (right?), as well as implementing the first API endpoint in that new service, this task is designed to give you a bit of a break, and to allow you to reflect on the power that CAP gives you out of the box, and on just some of the many wondrous aspects of OData.

Background

With all the functions and actions you’ve had to define and implement so far, it’s easy to forget what CAP gives you for free, when creating and serving services. And in terms of support for OData, a very accomplished and “complete” protocol, it is second to none, particularly with regards to the mechanisms you get for free.

The requirements

Here are the specific requirements for this task. Your Northbreeze service, still served via the OData V4 protocol, must respond appropriately to an OData QUERY operation that expresses a navigation from one entity to a related one, in the resource path. Specifically, it must respond to a request for an entity set of the Products belonging to a particular Supplier (see the Northwind and Northbreeze section of the previous task for details on these entity types).

In other words, your service needs to return an entity set containing products, for a specific supplier.

Some examples

Using the standard Northwind service, here are a couple of examples of that.

First, a list of the products belonging to the supplier with ID 22 (“Zaanse Snoepfabriek”): /Suppliers(22)/Products, which should produce:

{
  "@odata.context": "https://services.odata.org/V4/Northwind/Northwind.svc/$metadata#Products",
  "value": [
    {
      "ProductID": 47,
      "ProductName": "Zaanse koeken",
      "SupplierID": 22,
      "CategoryID": 3,
      "QuantityPerUnit": "10 - 4 oz boxes",
      "UnitPrice": 9.5000,
      "UnitsInStock": 36,
      "UnitsOnOrder": 0,
      "ReorderLevel": 0,
      "Discontinued": false
    },
    {
      "ProductID": 48,
      "ProductName": "Chocolade",
      "SupplierID": 22,
      "CategoryID": 3,
      "QuantityPerUnit": "10 pkgs.",
      "UnitPrice": 12.7500,
      "UnitsInStock": 15,
      "UnitsOnOrder": 70,
      "ReorderLevel": 25,
      "Discontinued": false
    }
  ]
}
Next, the products for supplier “Tokyo Traders” (ID 4), but just the product name and unit price: /Suppliers(4)/Products?$select=ProductName,UnitPrice, which should produce:
{
  "@odata.context": "https://services.odata.org/V4/Northwind/Northwind.svc/$metadata#Products(ProductName,UnitPrice)",
  "value": [
    {
      "ProductName": "Mishi Kobe Niku",
      "UnitPrice": 97.0000
    },
    {
      "ProductName": "Ikura",
      "UnitPrice": 31.0000
    },
    {
      "ProductName": "Longlife Tofu",
      "UnitPrice": 10.0000
    }
  ]
}

Back to the requirements

So your service must do this too. The great thing is, if you’ve set up your Northbreeze service as I recommended in the previous task (i.e. starting from a clone of the Northbreeze repo, then you’re already set, and don’t need to do anything specific to have the TESTER successfully test this in your service. That’s thanks to the power of CAP.

The service must be served using the OData V4 protocol, with the (default) path prefix /odata/v4 plus the service name northbreeze, and return an entity set of products belonging to a given supplier. Those products must be the correct ones (for example, products “Zaanse koeken” and “Chocolade” are the two products for supplier “Zaanse Snoepfabriek” (ID 22) and have the same IDs as they have in Northwind (as the TESTER will be checking the products returned in the entity set and examining the order of their IDs).

And that’s it!

As there is, in theory, nothing more for you to do in this task (except to submit to the TESTER as usual, see below), if you’ve correctly implemented the service for the previous task already, then why not use the remainder of your coffee time to consider the power of OData, and think about the answers to the following questions:

First, the Northwind service only allows the “traditional” OData key specification in the the resource path, e.g. /Suppliers(7) and not the more recent Key-as-Segment style. Does your Northbreeze service, powered by CAP, support that? What does that look like?

While we’re talking about resource paths, what about going one level deeper – is that supported? For example, Northwind supports paths such as /Products(70)/Category/CategoryName to get just the name of the category to which the product with ID 70 belongs. Does CAP support that too – can you do it with your Northbreeze service?

Even what one might think should be single scalar value responses, such as a category name like Beverages, come delivered inside some wrapping, by default in either an XML representation in the case of Northwind (extra whitespace added for readability):

<m:value 
    xmlns:d="http://docs.oasis-open.org/odata/ns/data" 
    xmlns:georss="http://www.georss.org/georss" 
    xmlns:gml="http://www.opengis.net/gml" 
    xmlns:m="http://docs.oasis-open.org/odata/ns/metadata" 
    m:context="https://services.odata.org/V4/Northwind/Northwind.svc/$metadata#Products(70)/Category/CategoryName">
    Beverages
</m:value>
or in a JSON representation in the case of the CAP powered Northbreeze equivalent:
{
  "@odata.context": "../../$metadata#Categories(1)/CategoryName",
  "value": "Beverages"
}
What if you wanted just the scalar value Beverages? Is that possible? If so, how?

On these questions and any related ones that occur to you – be sure to put your thoughts in the comments below!

Submitting to the TESTER

Now you’re ready to submit your CANDIDATE service to the TESTER!

The payload

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

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-Products"
}
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.

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.

Until the next task, have fun, and if you have any questions or comments, leave them below!

Scroll to Top