Skip to Content
Technical Articles

Developing a multi-experience app with MDK and CAP (Node.js)

Update 10/Feb/2021: Updated flow and screenshots to reflect updates in the CDS Graphical Modeler and SAP Business Application Studio.

In this blog post we will combine the Cloud Application Programming Model (CAP) with Multi-experience Development Kit (MDK) to build a full-stack application that can run in the desktop browser and in addition also as native apps on mobile.

In my previous blog post, I’ve created an MDK Web app that consumes an OData Service (Java) generated with Mobile Backend Tools. This time, we will use CAP to create a Node.js-based data service that uses the HANA database. We will also use the CDS Graphical Modeler to enhance the data model.

To make sure everyone can try this out, we will be using the SAP Cloud Platform Trial landscape. Having access to a productive landscape is actually better. I will highlight the differences later on.

Before you start, please ensure that your SAP Cloud Platform account has access to a HANA database. You can check this in the Service Marketplace of your subaccount. If this doesn’t show you a SAP HANA or SAP HANA Cloud service, then it will not be possible to deploy the data service we plan to create.

Disclaimer: what I am describing below, is a development flow that uses a non-protected data source. You should not apply this for productive use cases. For productive use cases, you need to deploy a protected data source and configure the authentication and authorization. As I wanted to keep the blog post as simple as possible, I’ve left out this part. I could cover this is topic in a follow-up blog post.

SAP Business Application Studio

As the IDE of choice, we will be using the SAP Business Application Studio. This allows us to set up a development environment with zero installation; you’ll only need a web browser.

In your web browser, open the SAP Cloud Platform cockpit page and follow the link in the Quick Tool Access section to open SAP Business Application Studio.Next, we need to create a container that includes all the relevant tools and extensions for our development. We call this a Dev Space. It is your development runtime in the cloud.

Please take note that for the Trial landscape, there are actually a couple of limitations:

  1. You cannot have more than 2 Dev Spaces.
  2. You cannot run more than 1 Dev Space at a time.

These limitations are less strict on productive landscapes (you can run multiple Dev Spaces simultaneously). So, if you have access to a productive landscape, please use that environment instead.

Another limitation, that currently applies to all productive landscapes is that we cannot combine the required extensions for CAP and MDK into a single Dev Space. This will be resolved in the coming months; but meanwhile we will have to split the development over two separate Dev Spaces.

Create one Dev Space for CAP and another one for Mobile (the name is actually not completely correct, as we can now go beyond mobile with MDK Web client). We’ll change that as well.For the Dev Space in which we will develop the CAP service, select the following option.
For developing the MDK application, use the following selection (the CDS Graphical Modeler is actually not required here).
Let’s start by creating the backend service for the application. For this we’ll open the CAP specific Dev Space.

 

CAP sample project

We will be leveraging an existing CAP project that was created for tutorials and has been referenced in online documentation and blog posts as well. The project is available on GitHub at https://github.com/SAP-samples/cloud-cap-samples and further information about this project is available in the project’s Readme available there.

After opening the Dev Space, select the option to “Clone from Git” on the Welcome page and provide the repository URL:

https://github.com/SAP-samples/cloud-cap-samples.git


This will trigger the opening of the console and shows the git clone being performed.

Using the console, navigate to the folder where the project is located and run the command npm install.For this blog post, we will focus on the bookshop service. Therefore, please open the workspace in the folder projects/cloud-cap-samples/bookshop.

Before we continue, we first need to fix an issue in the dependency list in the file package.json. Please remove the dependency “@capire/common”: “*”.

After opening the workspace, the left panel will show the (file) Explorer and also a CAP Project Explorer. You’ll probably need to expand the view to see which semantic models and representation files are in the project.

When you right-click on the Data Model ‘sap.capire.bookshop’, a context menu will give you the option to open the model with the CDS Graphical Modeler. This will open the CDS file located in the folder db, as visible in the file explorer.
To add a bit of flavoring to this project, let’s enhance the model a bit.

Right-click on the Books entity and select ‘Add Property’ in the context menu. The entity is missing the ISBN (International Standard Book Number). We’ll add this. The ISBN is a 13-digit number (which does not fit in an Integer), and some books may not have one. Hence, we allow null values.
What we are also missing, is an entity for Publishers. Right-click in the modeler’s canvas and select ‘Add Entity’ in the context menu.
Provide the name of the entity and press the Create button.You might not see the new entity in the visible area of the canvas. In that case, you can zoom in/out and pan the canvas to make it visible and move the entity to a better position.

We did not yet define any associations and properties for the Publishers entity. Let’s add them now. Select the Publishers entity, select ‘Add Property’ in the floating toolbar and add the name.A change from previous version of this blog post is that we now also have to manually add the entity’s key value.

Next, we’ll add the association. Again, right-click on the entity and select “Add Relationship” in the context menu. We’ll make this an Association with Many and select the Type sap.capire.bookshop.Books. For the Partner field, please enter the value manually.Next, we will define an annotation, to ensure this is a managed entity. Right-click on the entity and select “Add Annotation”. Select CDS in the list on the left and select “Include” in the detail list on the right. Click the “Add” button.In the menu for the @CDS.Include attribute, select Edit.Enter the string ‘managed’ and click Ok.The resulting model should look like this:

References: Design CDS Models Using SAP Business Application Studio, CAP Cookbook – Domain Modeling

Updating the sample data

In the folder db/data you will find a number of .csv files that contain sample data. Since we have added the ISBN number and the association to the Publishers entity, we need to update the file sap.capire.bookshop-Books.csv.

ID;ISBN;publisher_PublishersID;genre_ID;title;descr;author_ID;stock;price;currency_code
201;9780003700862;201;11;Wuthering Heights;"Wuthering Heights, Emily Brontë's only novel, was published in 1847 under the pseudonym ""Ellis Bell"". It was written between October 1845 and June 1846. Wuthering Heights and Anne Brontë's Agnes Grey were accepted by publisher Thomas Newby before the success of their sister Charlotte's novel Jane Eyre. After Emily's death, Charlotte edited the manuscript of Wuthering Heights and arranged for the edited version to be published as a posthumous second edition in 1850.";101;12;11.11;GBP
207;9780195811452;202;11;Jane Eyre;"Jane Eyre /ɛər/ (originally published as Jane Eyre: An Autobiography) is a novel by English writer Charlotte Brontë, published under the pen name ""Currer Bell"", on 16 October 1847, by Smith, Elder & Co. of London. The first American edition was published the following year by Harper & Brothers of New York. Primarily a bildungsroman, Jane Eyre follows the experiences of its eponymous heroine, including her growth to adulthood and her love for Mr. Rochester, the brooding master of Thornfield Hall. The novel revolutionised prose fiction in that the focus on Jane's moral and spiritual development is told through an intimate, first-person narrative, where actions and events are coloured by a psychological intensity. The book contains elements of social criticism, with a strong sense of Christian morality at its core and is considered by many to be ahead of its time because of Jane's individualistic character and how the novel approaches the topics of class, sexuality, religion and feminism.";107;11;12.34;GBP
251;9780143122364;203;16;The Raven;"""The Raven"" is a narrative poem by American writer Edgar Allan Poe. First published in January 1845, the poem is often noted for its musicality, stylized language, and supernatural atmosphere. It tells of a talking raven's mysterious visit to a distraught lover, tracing the man's slow fall into madness. The lover, often identified as being a student, is lamenting the loss of his love, Lenore. Sitting on a bust of Pallas, the raven seems to further distress the protagonist with its constant repetition of the word ""Nevermore"". The poem makes use of folk, mythological, religious, and classical references.";150;333;13.13;USD
252;9781974404759;204;16;Eleonora;"""Eleonora"" is a short story by Edgar Allan Poe, first published in 1842 in Philadelphia in the literary annual The Gift. It is often regarded as somewhat autobiographical and has a relatively ""happy"" ending.";150;555;14;USD
271;9780416654509;205;13;Catweazle;Catweazle is a British fantasy television series, starring Geoffrey Bayldon in the title role, and created by Richard Carpenter for London Weekend Television. The first series, produced and directed by Quentin Lawrence, was screened in the UK on ITV in 1970. The second series, directed by David Reid and David Lane, was shown in 1971. Each series had thirteen episodes, most but not all written by Carpenter, who also published two books based on the scripts.;170;22;15;EUR

 

Be careful not to add any empty lines to this file.

We also need to add a new .csv file for the Publishers entity, which contains the following sample data:

PublishersID;name
201;Addison-Wesley
202;Oxford University Press
203;Penguin Classics
204;Createspace Independent Publishing Platform
205;Methuen & Co. Ltd.

Updating the services

In the folder srv you will find a couple of files that define the data services and some implementation files. Since we’ve added the Publishers entity, we should update these files.

Open the file admin-service.cds in the CDS Graphical Modeler, right-click in the canvas and select “Add Projection”.

Provide the Name and select the Types. For the properties, use the default values.

Next, open the file cat-service.cds in the CDS Graphical Modeler and use the following steps to expose the new entity Publishers as read-only:

Right-click in the canvas and select “Add Projection”.

Provide the Name and select the Type. In the properties section, exclude the (managed) properties as shown here:

Select the newly created Entity and select “Add Annotation” in the floating toolbar.

In the ‘Add Annotation” dialog, select the CDS vocabulary and select the term ‘Annotations’. In the properties pane on the right side of the graphical modeler, select ‘Edit’.

In the Annotation editor, provide the string ‘@readonly’ and click ok.

Open the file admin-service.js in the code editor and add:

      this.before ('NEW','Publishers', genid)

Reference: CAP Cookbook – Services & APIs, CAP Cookbook – Generic Providers

Testing the service locally

Before we proceed with deploying the service, we will try and test it running locally using an SQLite database.

Navigate to the Run Configuration and add a new configuration by hitting the ‘+’ icon and selecting the bookshop (CAP) to run.You can create multiple run configurations with different parameters. Provide a name for the configuration we are going to create.The newly created configuration will show up in the list. Press the green play button to start the service.

Alternatively, you can also run the service by executing the following command in the console:

cds watch

If there are no errors reported, a popup will appear indicating “A service is listening to port 4004.”, and a button to “Open in New Tab”. Click on this button. If all goes well, you will see the following and you should be able to query the metadata and the data available via the service. You can even view the data via a Fiori Elements application. Take note that you will need to configure the settings to be able to see data.
When you click on the link /browse / $metadata or /admin / $metadata, you will see the OData service metadata document. You will notice the data entities, including the Publishers we’ve added.

When you click on the Books link, you will get the data as currently available in the database and should see values for the ISBN.

Deploying to Cloud Foundry

Following are the steps to create the SAP HANA service and deploying the bookshop service to Cloud Foundry.

First, make sure you are logged into the correct Cloud Foundry environment. In Business Application Studio, click on the status bar in the bottom left that mentions “Targeting CF….” or “The organization and space in CF have not been set”. You will be prompted to enter your credentials and select the organization and space.

Next, we are going to create the SAP HANA service, along with an HDI container and a database schema. Hit the F1 key to open the Command Palette and enter CF. From the list of commands shown, select CF: Create a new service instance.

Next, provide the name of the service instance. In this case we will use “bookshop-db”.

Next, select the Cloud Foundry service. If you are using a trial account, select “hanatrial”. Productive accounts should select “hana” here.

Next, select hdi-shared for the service plan.

Finally, we can provide additional parameters. We’ll skip this and just press ‘Enter’. The service will be created in the background.

To prepare for a ‘productive’ deployment, please add the following npm modules via the command line:

npm add --save @sap/hana-client @sap/xssec @sap/xsenv

Also, for this developer flow, we will deploy an non-protected service. Please do not use this for productive use cases.

Open the file package.json and auth strategy ‘dummy’. The cds section in the json structure should look like this:

  "cds": {
    "requires": {
      "db": {
        "kind": "sql"
      },
      "auth": {
        "strategy": "dummy"
      }
    }
  }

Now build the CDS project, using the command:

cds build --production

Next, push the generated HANA database service to Cloud Foundry using:

cf push -f gen/db

And finally, push the generated Node.js-based data service that interfaces with the database portion to Cloud Foundry using:

cf push -f gen/srv --random-route

If all succeeds, you will have a service up and running that can be accessed via a URL. To know the URL to be used, find the ‘routes’ mentioned in the console output.Copy the routes into a new browser tab. You should see:
Now that we have the data service up and running, we can start developing the MDK application. For that, we’ll need to switch to the other Dev Space we’ve created earlier. For those using the Trial landscape: open the Business Application Studio landing page and shut down the currently running Dev Space that we’ve used for CAP development.

Reference: CAP Cookbook – Using Databases, CAP Cookbook – Deploy to Cloud

Troubleshooting

The bookshop-srv service might fail to start. You can check for errors in the service’s logs by using the CLI:

cf logs --recent bookshop-srv

In some cases, it helps to restart this application using:

cf restart bookshop-srv

In case you are facing issues with the HANA deployment (applicable to SAP HANA Cloud instances), you might need to add the following in the package.json file (in the cds section):

        "hana": {
            "deploy-format": "hdbtable"
        },

Note: on the trial account, apps (which can be services) are stopped automatically after a while. If your app doesn’t respond, please go to the SAP Cloud Platform cockpit and check the running applications in your space (e.g. Trial Home – <youraccount> – trial – dev). The applications bookshop-srv and nsBookshopCustomerApp-router should be running.

Developing the MDK app

Start the ‘mobile’ dev space and once opened, click on the section in the bottom status bar that indicates “The organization and space in CF have not been set”. Provide your credentials and select the organization and space.

We will now focus on developing a simple app that customers can use in the book shop for checking whether books are available in the store. This app will make use of the ‘browse’ service, which exposes read-only data.

On the Welcome page, select ‘Start from Template’. Select the MDK Project template and click Start.
In the next step, we select the Base template type and provide a project name and application name. Select Next.Next, we need to provide information about the OData service we are going to consume. This is the service we’ve deployed to Cloud Foundry in the previous step. The Service URL needs to be the service url with /browse on the end (see screenshot below).After this, the project will be generated in your workspace and a popup in the bottom right will provide you the option to Open in New Workspace. Select this.

Note: in case you make changes to the CAP service after generating the MDK application, you should update the service metadata file Services/.bookshopbrowse.xml. Unfortunately, this needs to be done manually due to a bug.

After the workspace reloads and opens your project in the workspace, we need to create two pages, which we will organize in the subfolder ‘Books’.

Create a new folder called Books in the folder Pages and do the same in the folder Actions.

Right-click on the folder Pages/Books and select MDK: New Page in the context menu. In the Page Creation wizard, select the Section Page template.Click Next and provide a name for this page (e.g. BookList), then click Next and Confirm.The page editor will open. For this page, change the Caption in the Properties pane on the right to something else. For this example, I’ll change it to “Capire Books”.

We will now add a UI control onto the page. Expand the Compound list in the control pane on the left and drag and drop the Object Table control onto the page.

We will now configure this control to our needs. In the Properties pane on the left, do the following:

  • Select the Target service. You will only have one item selectable in the drop down, which is the data service we have configured during the project creation.
  • Select the EntitySet “Books”.
  • For one-to-many relationships, as is the case of genre, we can use the QueryOptions. Enter “$expand=genre,publisher”. You can also use the Query Options Expression Editor:
  • Change the Description to “{descr}”.
  • Clear the DetailImage field.
  • Change the Footnote to “{ISBN}”.
  • Set PreserveIconStackSpacing to false.
  • Clear the progress indicator.
  • Change status to “{price}” and substatus to “{currency_code}”.
  • Change subhead to “{author}”.
  • Change Title to “{title}”.
  • Set SearchEnabled to true.
  • To avoid triggering a search as soon as the user enters a character, we set the MinCharacterThreshold to 3 and add a 500 milisecond delay in SearchDelay.
  • In the SearchPlaceHolder, add “Search for books in this store …”

For some of the items you can actually use the Object Browser to pick the items.

When you are done, the control should look like this:If a user selects one the items in the list, another page should provide some more details. For this, we will create another page.

References: Mobile Development Kit online documentation.

Adding the detail page

Create a new page in the Pages/Books folder that is also based on the Section Page template and give it a name (e.g. BookDetails). Change the caption to “Capire Book Details”.

Drag and drop an Object Header (Container) control onto the page. Below this, drag and drop a Static Key Value (Container) control. In this control, drag and drop 2 Key Value Item (Container Item) controls.

Now let’s configure the Object Header:

  • Clear the BodyText.
  • Clear the Description
  • Clear DetailImage.
  • For Footnote – “ISBN: {ISBN}”.
  • For HeadlineText – “{title}”.
  • For Status – “$(C,{price},{currency_code},”,{minimumIntegerDigits:1,minimumFractionDigits:0,maximumFractionDigits:2,useGrouping:true})”.
  • For Subhead – “{author}”.
  • For Substatus – “{publisher/name}”.
  • For Tags, enter “{genre/name}”.

For the Key Value Items, we will use:

  • KeyName “Book description”, value “{descr}”.
  • KeyName “Currently in stock”, value “{stock}”.

Now that we have the pages created, we will define Actions that will help to navigate between them.

For this, create a new MDK Action in the folder Actions/Books and select the Navigation Action from the templates.Provide a name, select Next and Confirm.Create another Action for navigating to the BookList page.

Now that we have created the Actions, let’s change the Main Page and configure the page navigation.

Open the file Pages/Main.page. Change the caption (e.g. “Welcome to Capire Books”).

Drag and drop a Section Button Table control onto the page, and then drag and drop a Section Button into this control.

Change the Title of the Section Button to “Book Search”.

Activate the second tab in the right pane to show Events and click the button for the handler to open the Object Browser.In the Object Browser, select the Actions > Books > NavToBookList.action and click Insert. Then click OK.Open the BookList page and for the Object Table, bind the OnPress event handler to the NavToBookDetails.action.

Deploying the MDK Web app

Now that we have configured the pages and navigation, it is time to see our app in action.

Right-click on the file Application.app and select MDK: Deploy. Select Cloud Foundry as deployment target. Select the default values and watch the application getting built and deployed. As part of the build process, an MTA archive will be created. The deployment of the MTA will trigger the creation of:

  • an html repository host and runtime
  • an xsuaa service for handling the authentication and authorization
  • a destination
  • a connection service
  • an approuter
  • an application UI deployer

And as part of the deployment, we will bind all these pieces together for you.

Once this is done and successful, click on the button in the bottom right to Open the app.

The web application should show you the following screens:

Welcome page:

Book overview and search page:

Book detail page:

I will skip the deployment to mobile in this blog post. If you want to know the steps, please refer to my previous blog post.

Conclusion

I’ve shown you the end-to-end flow for developing a full-stack application. Unfortunately, we could not develop this in one single Dev Space, and we had to work around some quirks. In the coming months you can expect updates that will resolve this, so you can work in one single cloud development environment.

We are also working on improving the low code developer experience and flows.

Feedback is welcome, and if this blog post was useful to you, please leave a Like.

Regards,
Ludo Noens

 

4 Comments
You must be Logged on to comment or reply to a post.
    • Hi Jason,

      Thanks for the feedback !

      I've tried to keep the blog post simple, as the authentication topic is rather non-trivial.

      In case of a protected service, we'll need to capture the EDMX describing the data source and load it as local file into the MDK Project creation wizard. Then during deployment of the application we would need to wire up and configure everything (XSUAA, approuter, destination, etc.). We are looking into automating this flow.

      Regards,
      Ludo

  • Hi Ludo. Thanks for your blog.

    I get the following error when I deploy the bookshop service on hana (step:  cf push -f gen/srv --random-route):

    It seems lt doesn't find hana however the service is running.

    I already included:

    "hana": {
    "deploy-format": "hdbtable"
    }

    but It didn't change anything.

    Some idea?

    Thanks

    Regards,

    Francisco.

    /