Technology Blogs by SAP
Learn how to extend and personalize SAP applications. Follow the SAP technology blog for insights into SAP BTP, ABAP, SAP Analytics Cloud, SAP HANA, and more.
Showing results for 
Search instead for 
Did you mean: 
Developer Advocate
Developer Advocate
This is a searchable description of the content of a live stream recording, specifically "Episode 5 - Continuation of the CAPM Node.js bookshop tutorial" in the "Hands-on SAP dev with qmacro" series. There are links directly to specific highlights in the video recording. For links to annotations of other episodes, please see the "Catch the replays" section of the series blog post.

This episode, titled "Continuation of the CAPM Node.js bookshop tutorial", was streamed live on Wed 13 Feb 2019 and is approximately one hour in length. The stream recording is available on YouTube.

Below is a brief synopsis, and links to specific highlights – use these links to jump directly to particular places of interest in the recording, based on ‘hh:mm:ss’ style timestamps.

Brief synopsis

We continue working our way through the tutorial “Create a Business Service with Node.js using Visual Studio Code” on the SAP Developer Centre.

00:04:02: I'm using the 3270 font by Ricardo Bánffy in my terminal.

00:05:22: Noted what happened since last time we looked at the tutorial, which was live stream episode 3 where we had Christian Georgi on as a guest, live stream episode 4 where we looked at the CDS REPL, and the fact that CDS has been updated.

00:06:00: Looking briefly at the CDS update from 3.0.0 to 3.5.0.

00:07:39: Looking at the environment shortcuts I have for my shell and for ranger, via alias settings that are controlled by a scripts mechanism that I have in my scripts repo. I also note that my Vim configuration is also available in my dotvim repo.

00:09:35: Discussion of whether we can have a lowest-common-denominator style configuration that can work across different environments. It's easier with *nix style environments like Linux, macOS and the Linux VM on Chrome OS, and perhaps possible with the Windows subsystem for Linux too.

00:11:00: Looking at the @Sap/cds module with npm list and npm info.

00:12:00: Start a fresh project with cds init my-bookshop.

00:12:32: A brief exploration of what we have in project generated by running cds init, including cds.js and launch.json in the .vscode directory, and the common.cds file inside the @Sap/cds module within the node_modules directory.

00:14:38: Noting that the contains a nice tutorial which is similar to the one we're following.

00:15:05: An overview of the db/srv/app directory name convention in the programming model, and what they are for, and the subtle difference between data definitions in db, and services, for example with an OData flavour, in srv.

00:16:35: Creating srv/cat-service.cds, which at this stage includes the definition of the entities that would normally go in the data model (in the db directory).

00:17:00: Creating the service implementation that provides mock data, noting the fact that the convention is that a js file with the same name as the cds file will provide implementation logic for that service.

00:17:54: Chocolate treat fail.

00:18:28: Considering the advantages of ES6 (the 2015 version of JavaScript, effectively) is that some of the constructs allow us to read and write code that flows much more easily when we see it. Case in point here is the srv.on ('READ', 'Books', ()=>[ ... ]) construction.

00:19:45: Adding a console.log statement to the second function definition in cat-service.js, expanding the single-expression in the fat arrow definition to a block so we can add a second statement.

00:20:14: A plugin for VS Code that integrates with Twitch to allow participants to cause lines of code to be highlighted:

00:20:37: Idea of us using Live Share on a future episode to collaborate live in the stream on some code.

00:21:05: Currently the service definition contains the entity definitions, which really belong in the data model, not the service. Note, however, that creating a high level service definition is a great way to bootstrap a project, because everyone is on the same page and then two parallel streams of activities can take place after the basic idea has been established - refining the data model and service(s) and building out the UI (based on the service metadata).

00:22:30: Starting up VS Code's integrated terminal with the shortcut Cmd-`. Also a small ramble about mechanical keyboards, I'm using a Vortex Race 3 with Cherry MX Blue switches, and have an Anne Pro 2 with Gateron Brown switches on order.

00:23:01: Starting up the service with cds run, noting the small difference that we see in the log output from 3.5.0, compared to what we previously saw with 3.0.0, specifically the "serving static resources from ./app" line. We also note that another line of the log output points to a JS implementation for the CatalogService, in cat-service.js.

00:24:26: Adding a breakpoint to the srv.on ('READ', 'Authors', () => { ... }) section in cat-service.js, then a first attempt at running the service in debug mode. The attempt fails, and we look at a solution based on the information in launch.json and cds.js within the .vscode directory.

00:25:51: Making debugging work by replacing the contents of cds.js with:
const cds = require('@sap/cds')

Debugging launches successfully after this change.

00:27:08: Noting that the indicator on the browser tab is still spinning, followed by a random reminicence, remembering the fact that the indicator on a browser that showed that resources were still being retrieved on a page was called a "throbber", which I remember from the Cello, Viola and Netscape Navigator browsers of yesteryear.

00:28:50: Starting to modify the service definition by moving the entity definitions out of cat-service.cds into db/data-model.cds.

00:30:15: Noting a (new) bug in VS Code where a newly minted directory (db/), created implicitly when we add that directory name as a path to a new file, doesn't show up immediately in the Explorer.

00:31:30: At this point we have the srv/cat-service.cds definitions as views, as a series of projections, on individual entity definitions in db/data-model.cds. These are known as API facades to the entities in the data model, controlling what is and isn't exposed, also restricting access via annotations.

00:32:58: Calling up the Command Palette (Shift-Cmd-P) to use the Refresh facility, which will force a refresh of the Explorer display. Great, thanks Ronnie!

00:34:00: Looking briefly at the CDS annotations in the projections, specifically @readonly and @insertonly that restrict operation access.

00:34:32: Now it's time to generate the SQL DDL to deploy to an actual persistence layer, in this case based on SQLite.

00:35:12: We open up package.json to see what gets added when we install the sqlite3 module as a development dependency (with the -D or --save-dev options).

00:37:22: Looking at the cds command options, and compiling the db/data-model.cds definitions. The default output (in the form of Core Schema Notation (CSN) is shown).

00:38:26: We also look at getting the output in SQL with the --to sql option (-2 can be used as a shortcut for --to), plus look at the compiled output for the srv/cat-service.cds where we see that TABLE and VIEW creation statements have been generated, noting the names of the views as projections (SELECT ... FROM) on tables.

00:40:20: Deploying the definitions to the persistence layer like this:
cds deploy --to sqlite:db/my-bookshop.db

and noting a new stanza appearing in the package.json file that describes the database.

00:41:19: Answering a question about the relationship between the namespace my.bookshop declaration and the underlying database, including looking at what happens to the generated DDL statements when we temporarily change the namespace definition to my.banana.

00:43:14: At this stage we have our data model and service deployed to the persistence layer, so we have a look around with the sqlite command line client, using the .dump command to see the data definitions. We also tried to look at the database with the SQLite extension for VS Code but there was a strange issue with that for some unknown reason (it has been working very well for me until now).

00:47:09: Adding some initial data by supplying it in CSV files (in a csv/ directory within db/) that follow a specific naming convention, which is based on the fully qualified table names - for example my.bookshop-Authors.csv.

00:49:10: Deploying again, we see a new message "initializing from csv files at ./db/csv..." and when we inspect the statements with .dump again in sqlite3 we see INSERT statements for the data.

00:49:55: We can now remove the static data implementation in srv/cat-service.js (we didn't remove the file itself, which means that we still get an "impl: cat-service.js" message when we execute cds run but of course that's only because the file is still there (but empty).

00:50:48: We now check to see if there are any books available via the service on localhost, and indeed there are - the data is coming from the database.

00:51:28: Firing up Postman to load in a collection of test requests - we do this directly from the collection URL rather than downloading the file and uploading it into Postman (see "Monday morning thoughts: upload / download in a cloud native world" for more on this).

00:52:10: Using some of the OData requests in the collection to test the service.

00:53:00: Adding some custom logic to the (currently empty) srv/cat-service.js implementation file. It also adds a discount when books are retrieved, using a special version of the callback with the each parameter for the function definition.

00:55:42: Restarting the service in debug mode and testing it via Postman, checking first the stock for one of the books, then placing an order for that book, inspecting thereafter the stock level.

00:56:50: Looking briefly at the UUID type (in node_modules/@sap/cds/common.cds), which will be used in the order operations we're about to perform.

00:58:51: Debugging the implementation for the srv.before ('CREATE', 'Orders', async (req) => { ... }) and inspecting the incoming request that was received.

00:59:48: Noting that the mechanism to reduce stock when books are ordered has the success of the order (and reduction) controlled with a .where clause in the fluid API of CAPM's CDS Query Language (CQL).