Orchestrate

Set up for Unit 6: app tooling: Node.js, CAP and Cloud Foundry

Install Node.js, SAP's CAP development kit, the Cloud Foundry CLI and FastAPI, log in to your BTP trial from the terminal, and run a tiny API both ways.

Updated Oct 2, 2026Foundational 7 minDeep 40 min
Foundational layer · 7 min read

The 60-second version

Until now, every script in this course ran once and stopped. Unit 6 turns that work into applications: programs that stay running and answer requests from other systems, such as an SAP Fiori app, a workflow or another service.

That takes a few new tools on the learner's laptop:

  • Node.js, a way to run JavaScript outside a browser. SAP's main framework for business apps runs on it.
  • CAP, the SAP Cloud Application Programming Model, installed as a small command-line kit. It builds business services from a short data model.
  • The Cloud Foundry command-line tool, called cf. It talks to the Cloud Foundry runtime inside SAP Business Technology Platform (BTP), where Unit 6 deploys apps.
  • FastAPI, a Python library for building web APIs. The course uses it for the AI service in the next topic.

All four are free. Setup takes 45 to 75 minutes. At the end, the learner runs one tiny API in Python and one in CAP, and logs in to their BTP trial from the terminal.

Why it matters to the business

A model call in a notebook helps one person. A model call behind an API (a defined way for programs to ask for something) helps every system that can call it. That step, from script to service, is where most AI pilots stall.

Three points matter to a leader:

  • Two toolchains are normal. AI teams often write the AI part in Python. SAP extensions are often written with CAP on Node.js. Unit 6 sets up both, so the team can choose per use case rather than by habit.
  • Deployment is a skill, not a step. Running an app on BTP needs an account, a login, and the right org and space. Practising this on a free trial avoids learning it on a customer's system.
  • Versions are a support question. Node.js has a published support schedule, and CAP states which Node.js versions it supports. Picking a supported version now avoids an unplanned upgrade mid-project.

Picture the running example, blocked sales orders in order-to-cash. In Unit 6 the "explain this blocked order" prompt becomes a small service. A credit clerk's screen could call it, and it could run on BTP next to the company's other extensions.

How SAP does it

As of October 2026:

  • CAP is SAP's framework for building business services and applications on BTP. Its current major release is cds 10. SAP's release notes make Node.js 22 the minimum and recommend Node.js 24.
  • Node.js 24 is the long-term support (LTS) line. Node.js 26 came out in May 2026 and is in its "Current" phase. The Node.js project says production apps should use LTS releases only.
  • Cloud Foundry is one of the runtimes in a BTP subaccount. The learner's BTP trial from Set up for Unit 3 already has a Cloud Foundry org and a dev space. SAP's documentation says to log in with the cf tool and your SAP account.
  • SAP Business Application Studio is SAP's browser-based development environment. A trial user can open it from the BTP cockpit. It is an option when a laptop is locked down, but this course installs the tools locally.

What this unit adds

Tool What it is Cost Used in
Node.js 24 (LTS) and npm Runs JavaScript; npm installs JavaScript packages Free CAP and side-by-side extensions
CAP development kit (@sap/cds-dk) SAP's command-line kit for CAP projects Free CAP and side-by-side extensions; deployment
Cloud Foundry CLI v8 (cf) Talks to Cloud Foundry on BTP Free Deploying AI apps on SAP BTP
FastAPI Python library for web APIs Free Building an AI API
Your BTP trial (from Unit 3) Where apps get deployed Free, time-limited Deploying AI apps on SAP BTP

Unit 6 topics that call a model use the SAP generative AI hub access from Set up for Unit 5. That trial lasts 30 days, so a learner may no longer have it. Those topics offer sample paths that need no model access.

Time and money

  • Time: 45 to 75 minutes. Installers take most of it. The login and smoke tests take about 15 minutes.
  • Money: nothing. All tools are free, and the BTP trial costs nothing.
  • Disk space: a few hundred megabytes for Node.js, the CAP kit and FastAPI.
  • Trial clock: the BTP trial from Unit 3 lasts up to 90 days and is suspended after 30 days without a sign-in. If it has ended, a learner can create a new one.

Questions to ask IT

  • May learners install Node.js and the Cloud Foundry CLI? Do they need local admin rights to do it?
  • Does the company network allow npm's package registry and the SAP BTP Cloud Foundry addresses?
  • Does the company proxy need settings for npm or cf, and who can give them?
  • Is SAP Business Application Studio available, if laptops can't run local installs?
  • Which Node.js version do the company's own CAP projects use, and when do they plan to move to the next LTS?

Common misconceptions

  • "CAP needs Java." CAP has a Java flavour, but SAP's setup guide marks Java and Maven as optional. This course uses the Node.js flavour.
  • "Use the newest Node.js." The newest line is not always supported for production. As of October 2026, CAP recommends Node.js 24, the LTS line.
  • "You need a paid BTP account to deploy." The free trial has a Cloud Foundry org and space for learning. It is not for production or team work.
  • "Python and CAP compete." They solve different parts. Python suits the AI logic; CAP suits business services that look and behave like SAP's own.

Key terms

  • API: a defined way for one program to ask another for data or an action, usually over the web.
  • Node.js: a program that runs JavaScript outside a browser; CAP's Node.js flavour runs on it.
  • npm: the package installer that comes with Node.js.
  • LTS (long-term support): a Node.js release line that gets fixes for a long, published period.
  • CAP: the SAP Cloud Application Programming Model, SAP's framework for business services on BTP.
  • CDS: Core Data Services, the short language CAP uses to describe data and services.
  • Cloud Foundry: a runtime in SAP BTP that runs apps; its tool is cf.
  • Org and space: Cloud Foundry's folders for apps; a trial has one org and a space named dev.
  • FastAPI: a Python library for building web APIs, with automatic documentation pages.

Check yourself

Pick one answer for each question. The explanation appears after you choose.
  1. 1What does Unit 6 change about how the learner's work runs?

    Answer: A. Unit 6 turns a model call into an application that other systems can call through an API. Python stays for the AI part; CAP and Cloud Foundry are added for SAP-style services and deployment.
  2. 2A team asks why the course installs both FastAPI and CAP. What is the best answer?

    Answer: C. AI teams often write the AI part in Python, and SAP extensions are often built with CAP on Node.js. Setting up both lets a team pick per use case.
  3. 3Which Node.js version should a new CAP project use as of October 2026?

    Answer: D. SAP's CAP release notes make Node.js 22 the minimum and recommend Node.js 24. Node.js 26 is still in its "Current" phase, and the Node.js project says production apps should use LTS releases.
  4. 4A partner proposes running the pilot on the learner's BTP trial. What is the problem?

    Answer: B. The trial has a Cloud Foundry org and dev space, which is enough to learn deployment. SAP rules out production and team use, and the trial ends, so a pilot needs a proper account.
  5. 5Laptops at your company block software installs. What is a sensible question for IT?

    Answer: D. SAP Business Application Studio runs in the browser and can be opened from the BTP cockpit. It avoids local installs, though this course's steps assume local tools.
  6. 6What does Unit 6's setup cost in money?

    Answer: C. Node.js, the CAP kit, the cf tool and FastAPI are all free, and so is the BTP trial. Only model calls in later topics can cost money, and those offer sample paths.
Deep layer · 40 min read

Mental model: two toolchains on your laptop, one runtime in the cloud

Unit 6 adds a second way to build. Python stays for the AI logic, now wrapped in a web API with FastAPI. Node.js arrives to run CAP, SAP's framework for business services. The cf tool connects both to Cloud Foundry in your BTP trial, where later topics deploy them.

flowchart LR
  subgraph Laptop
    P[Python + FastAPI<br/>hello_api.py] 
    N[Node.js + CAP<br/>hello-cap]
    C[cf CLI]
  end
  P -->|localhost:8000| B[Browser or caller]
  N -->|localhost:4004| B
  C -->|cf login| CF[Cloud Foundry<br/>BTP trial org + dev space]

Today both APIs run only on your computer. The deployment topic later in Unit 6 moves them to Cloud Foundry. This setup proves each piece works on its own first.

How it works

Node.js and npm

Node.js runs JavaScript outside a browser. It comes with npm, a package installer, much like pip for Python. npm installs packages in two ways:

  • Globally (npm add -g ...): a command-line tool you can run from any folder. The CAP kit is installed this way.
  • Locally (inside a project's node_modules folder): libraries one project needs. CAP projects use this later.

Node.js publishes a support schedule. As of October 2026, the Node.js releases page lists v24 (codename Krypton) as LTS and v26 as Current. It says production apps should use only Active LTS or Maintenance LTS releases. CAP's June 2026 release notes match: Node.js 22 is the minimum, 24 is recommended, and 26 is tested and usable in development.

CAP and the CDS language

CAP projects describe data and services in CDS (Core Data Services) files. The CAP kit, @sap/cds-dk, gives you the cds command. Three commands matter now:

Command What it does
cds version Prints the installed CAP versions and where Node.js and npm live
cds init <name> Creates a project folder with app/, db/ and srv/
cds watch Runs the project, restarts on every change, and serves it at http://localhost:4004

In our test, cds watch used an in-memory SQLite database and loaded sample rows from a CSV file. The file name follows the pattern <namespace>-<Entity>.csv in db/data/. Each service is served as OData version 4 under /odata/v4/. OData is the web API style SAP systems use, which you met in Calling your first SAP API.

Cloud Foundry and the cf tool

Your BTP trial subaccount has one Cloud Foundry org and one space, dev, as Set up for Unit 3 showed. The cf tool talks to Cloud Foundry's API endpoint, a web address shown on your subaccount's Overview page.

SAP's documentation describes two steps: point cf at the endpoint, then log in with the email and password of your SAP account. When your account uses two-factor sign-in or single sign-on, cf login --sso prints a web address instead. You open it, sign in in the browser, and paste back a one-time passcode.

After login, cf saves your session in a file named config.json in a .cf folder in your home folder. It holds a sign-in token, so treat that folder like a password.

FastAPI and Uvicorn

FastAPI is a Python library for web APIs. You write normal Python functions and mark each with the address it answers, such as @app.get("/health"). FastAPI checks incoming data against Pydantic models (Python classes that describe the expected fields) and builds documentation pages at /docs.

Uvicorn is the web server that runs a FastAPI app. The fastapi[standard] install brings it along, plus the fastapi command. fastapi dev runs your app with auto-reload, restarting it whenever you save.

Build it yourself: install the Unit 6 tools and run a tiny API both ways

You will install Node.js, the CAP kit, the cf tool and FastAPI. Then you will run a small blocked-orders API in Python, the same data in CAP, log in to your BTP trial, and run a check. Everything except Step 5 works without any account.

Before you start: complete Set up your computer for this course, Set up for Unit 2 and Set up for Unit 3. They install Python, VS Code and Git, create your orchestrate-course folder with its .venv, and create your SAP BTP trial. This walkthrough doesn't repeat those steps.

What you need

  • Your course folder from earlier units.
  • About 45 to 75 minutes.
  • Your SAP BTP trial and its notes from Unit 3 (the API endpoint and org name). Only Step 5 needs it.
  • Cost: free.

Step 1: Open your course folder and turn on the virtual environment

  1. Open VS Code, choose File > Open Folder, and open orchestrate-course.

  2. Open a terminal: Terminal > New Terminal.

  3. If the prompt doesn't start with (.venv), turn it on:

    • Windows (PowerShell):

      .venv\Scripts\Activate.ps1
    • macOS / Linux:

      source .venv/bin/activate

Run every command in this topic from the course folder unless a step says otherwise.

Step 2: Install Node.js 24 (LTS)

  1. Open https://nodejs.org/en/download in your browser. It offers the LTS version by default; as of October 2026 that is v24.

  2. Install it:

    • Windows: download the Windows Installer (.msi) for your machine (x64 for most laptops, ARM64 for ARM laptops). Run it and accept the defaults.
    • macOS: download the macOS Installer (.pkg). Run it and accept the defaults.
    • Linux: choose Linux on the download page and run the commands it shows for your system.
  3. Close VS Code's terminal and open a new one (Terminal > New Terminal), so it sees the new PATH. Turn on .venv again as in Step 1.

  4. Check both tools (the same on every system):

    node --version
    npm --version

What success looks like (your numbers may be higher):

v24.21.0

followed by npm's own version number on the second line. Any v24 line is right. v22 also works for CAP but is the older line. If you see v20 or lower, install v24; CAP 10 no longer supports Node.js 20.

Step 3: Install the CAP development kit

  1. Install it globally with npm (the same on every system):

    npm add -g @sap/cds-dk

    This takes a minute or two. Warnings about funding or a newer npm are normal.

  2. Open a new terminal again, turn on .venv, and check:

    cds version

What success looks like (from our test, which ran Node.js 22; your paths and versions will differ):

  @sap/cds-dk (global)  10.1.0   /home/you/.npm-global/lib/node_modules/@sap/cds-dk
  cds.home                       /home/you/.npm-global/lib/node_modules/@sap/cds-dk/node_modules/@sap/cds
  cds.root                       /home/you/orchestrate-course
  npm root -l                    ./node_modules
  npm root -g                    /home/you/.npm-global/lib/node_modules
  Node.js               22.22.0  /opt/node22/bin/node
  npm                   10.9.4   /opt/node22/bin/npm

The line that matters is @sap/cds-dk (global) with a version starting 10..

  1. In VS Code, open the Extensions view (the four-squares icon on the left), search for sapse.vscode-cds and click Install. It is SAP's CDS language support: colours, completion and error marks in .cds files.

Step 4: Install the Cloud Foundry CLI v8

  • Windows:

    1. Open the v8 installation guide: https://github.com/cloudfoundry/cli/wiki/V8-CLI-Installation-Guide.
    2. Under the Windows section, download the zip installer (64-bit).
    3. Unzip it, run the installer inside, and accept the defaults.
    4. If you use Chocolatey, choco install cloudfoundry-cli is the guide's alternative.
  • macOS (with Homebrew, from https://brew.sh):

    brew install cloudfoundry/tap/cf-cli@8
  • Linux (Debian or Ubuntu):

    wget -q -O - https://packages.cloudfoundry.org/debian/cli.cloudfoundry.org.key | sudo gpg --dearmor -o /usr/share/keyrings/cli.cloudfoundry.org.gpg
    echo "deb [signed-by=/usr/share/keyrings/cli.cloudfoundry.org.gpg] https://packages.cloudfoundry.org/debian stable main" | sudo tee /etc/apt/sources.list.d/cloudfoundry-cli.list
    sudo apt-get update
    sudo apt-get install cf8-cli
  • Linux (Fedora or RHEL):

    sudo wget -O /etc/yum.repos.d/cloudfoundry-cli.repo https://packages.cloudfoundry.org/fedora/cloudfoundry-cli.repo
    sudo yum install cf8-cli

Open a new terminal, turn on .venv, and check:

cf version

What success looks like (from our test; your version may be newer):

cf version 8.18.4+3fcd823.2026-07-02

The v8 tool is installed as cf8 with a shortcut named cf. Either name works; this course uses cf.

Step 5: Log in to your BTP trial from the terminal

You need the API endpoint you wrote down in Unit 3. If you don't have it: open the SAP BTP cockpit, go to your trial subaccount, and on the subaccount's Overview page, find the Cloud Foundry section and copy the API endpoint.

  1. Log in, replacing the address with your own endpoint:

    cf login -a https://api.cf.YOUR-REGION.hana.ondemand.com
  2. When asked for your email, type the email of your SAP account. When asked for your password, type it; nothing shows while you type. That is normal.

  3. If you are asked to pick an org or a space, pick your trial org and dev.

If the password is refused even though it is right, your account probably uses two-factor sign-in or single sign-on. Use the one-time passcode route:

  1. Run:

    cf login -a https://api.cf.YOUR-REGION.hana.ondemand.com --sso
  2. cf prints a web address and asks for a passcode. Open the address in your browser and sign in with your SAP account.

  3. The page shows a one-time code. Copy it, paste it at cf's passcode prompt and press Enter. It may not show while you paste.

Then confirm where you are:

cf target

What success looks like (shape only; we couldn't reach SAP's servers from our test environment, so your values and labels may differ slightly):

API endpoint:   https://api.cf.YOUR-REGION.hana.ondemand.com
API version:    3.x
user:           you@example.com
org:            a1b2c3d4trial
space:          dev

No SAP access right now? Skip this step. The check in Step 8 marks it LATER, and nothing else in this setup depends on it.

Step 6: Install FastAPI and run a tiny Python API

The script below is a small web API over three made-up blocked sales orders. It has a health check, a list, and an /explain endpoint that returns a fixed sentence. In the next topic, Building an AI API, a model writes that sentence instead.

  1. Open requirements.txt and add this line at the end, then save:

    fastapi[standard]
  2. Install:

    pip install -r requirements.txt
  3. Make the Unit 6 folder:

    • Windows (PowerShell):

      New-Item -ItemType Directory -Force unit06
    • macOS / Linux:

      mkdir -p unit06
  4. In VS Code, right-click unit06, choose New File, name it hello_api.py, paste the code below and save.

"""Unit 6 smoke test: a tiny web API in Python, built with FastAPI.

It answers three requests about made-up blocked sales orders. There is no model call yet;
"Building an AI API" puts one behind the /explain endpoint.

How to run (from your course folder, with .venv turned on):
    python unit06/hello_api.py                 # starts the API at http://127.0.0.1:8000
    python unit06/hello_api.py --port 8080     # use another port if 8000 is taken
Stop it with Ctrl+C.
"""
import argparse

from fastapi import FastAPI, HTTPException
from pydantic import BaseModel

BLOCKED_ORDERS = {   # made-up data in the shape of the course's running example
    "4711": {"customer": "Made-up Retail GmbH", "reason": "Credit limit exceeded", "net_value": 12500.00, "currency": "EUR"},
    "4712": {"customer": "Example Foods Ltd", "reason": "Missing export documents", "net_value": 8300.50, "currency": "GBP"},
    "4713": {"customer": "Sample Tools Inc", "reason": "Credit limit exceeded", "net_value": 21000.00, "currency": "USD"},
}

app = FastAPI(title="Orchestrate Unit 6 hello API", version="0.1.0")


class ExplainRequest(BaseModel):
    """What a caller sends to /explain: the sales order number."""
    sales_order: str


@app.get("/health")
def health() -> dict:
    """A quick 'are you alive?' check that platforms such as Cloud Foundry can call."""
    return {"status": "ok"}


@app.get("/blocked-orders")
def blocked_orders() -> list:
    """List the made-up blocked orders."""
    return [{"sales_order": number, **order} for number, order in BLOCKED_ORDERS.items()]


@app.post("/explain")
def explain(request: ExplainRequest) -> dict:
    """Return a plain-words explanation. A fixed sentence for now; an LLM writes it in the next topic."""
    order = BLOCKED_ORDERS.get(request.sales_order)
    if order is None:
        raise HTTPException(status_code=404, detail=f"No blocked order {request.sales_order} in the sample data")
    text = (f"Order {request.sales_order} for {order['customer']} is blocked: {order['reason'].lower()}. "
            "Ask the responsible team to review it before it can ship.")
    return {"sales_order": request.sales_order, "explanation": text, "source": "template (no model yet)"}


if __name__ == "__main__":
    import uvicorn

    parser = argparse.ArgumentParser(description="Run the Unit 6 hello API on your computer.")
    parser.add_argument("--port", type=int, default=8000, help="port to listen on (default 8000)")
    args = parser.parse_args()
    print(f"Open http://127.0.0.1:{args.port}/docs in your browser. Press Ctrl+C to stop.")
    uvicorn.run(app, host="127.0.0.1", port=args.port)
  1. Start it:

    python unit06/hello_api.py

What success looks like:

Open http://127.0.0.1:8000/docs in your browser. Press Ctrl+C to stop.
INFO:     Started server process [957]
INFO:     Waiting for application startup.
INFO:     Application startup complete.
INFO:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)

The terminal now stays busy: the API is running. That is the difference from every earlier script.

  1. Open http://127.0.0.1:8000/docs in your browser. You see FastAPI's documentation page with your three endpoints. Click POST /explain, then Try it out, change the body to {"sales_order": "4711"} and click Execute.

  2. Or call it from a second terminal (Terminal > New Terminal; the first one is busy):

    • Windows (PowerShell):

      Invoke-RestMethod http://127.0.0.1:8000/health
      Invoke-RestMethod -Method Post -Uri http://127.0.0.1:8000/explain -ContentType "application/json" -Body '{"sales_order": "4711"}'
    • macOS / Linux:

      curl http://127.0.0.1:8000/health
      curl -X POST http://127.0.0.1:8000/explain -H "Content-Type: application/json" -d '{"sales_order": "4711"}'

What success looks like (macOS/Linux; PowerShell shows the same values as a small table):

{"status":"ok"}
{"sales_order":"4711","explanation":"Order 4711 for Made-up Retail GmbH is blocked: credit limit exceeded. Ask the responsible team to review it before it can ship.","source":"template (no model yet)"}

Ask for order 9999 and you get {"detail":"No blocked order 9999 in the sample data"} with status 404. That is the API working correctly: it says clearly that the order isn't there.

  1. Go back to the first terminal and press Ctrl+C to stop the API.

What each part of the script does:

Part What it does
BLOCKED_ORDERS Three made-up orders, shaped like the course's running example
app = FastAPI(...) Creates the web app; the title appears on the /docs page
ExplainRequest A Pydantic model: callers must send a sales_order text field, or FastAPI rejects the request with status 422
@app.get("/health") A quick "are you alive?" endpoint, the kind platforms call to check an app
@app.get("/blocked-orders") Returns the list as JSON
@app.post("/explain") Looks up the order and returns a sentence; returns 404 if the order isn't there
uvicorn.run(...) Starts the web server on your own computer only (127.0.0.1)
--port Optional: another port if 8000 is taken

Step 7: Run the same data as a CAP service

Now the same blocked orders, as a CAP service. You write no code: two short CDS files and a CSV file are enough.

  1. In the terminal, go into unit06 and create a CAP project (the same on every system):

    cd unit06
    cds init hello-cap
    cd hello-cap

    What success looks like:

    Successfully initialized CAP project

    The new folder unit06/hello-cap has app, db and srv folders, a readme.md and its own .gitignore.

  2. In VS Code, in unit06/hello-cap/db, create schema.cds, paste this and save:

namespace course;

entity BlockedOrders {
  key salesOrder : String(10);
      customer   : String(80);
      reason     : String(120);
      netValue   : Decimal(15, 2);
      currency   : String(3);
}
  1. In unit06/hello-cap/db, create a folder named data. In it, create course-BlockedOrders.csv, paste this and save. The name must match exactly: the namespace course, a dash, then the entity name.
salesOrder,customer,reason,netValue,currency
4711,Made-up Retail GmbH,Credit limit exceeded,12500.00,EUR
4712,Example Foods Ltd,Missing export documents,8300.50,GBP
4713,Sample Tools Inc,Credit limit exceeded,21000.00,USD
  1. In unit06/hello-cap/srv, create service.cds, paste this and save:
using course from '../db/schema';

service OrdersService {
  @readonly entity BlockedOrders as projection on course.BlockedOrders;
}
  1. Start it (from unit06/hello-cap):

    cds watch

What success looks like (trimmed; from our test):

[cds] - loaded model from 2 file(s):
  srv/service.cds
  db/schema.cds
[cds] - connect to db > sqlite { database: ':memory:' }
  > init from db/data/course-BlockedOrders.csv
/> successfully deployed to in-memory database.
[cds] - serving OrdersService {
  at: [ '/odata/v4/orders' ],
  decl: 'srv/service.cds:3'
}
[cds] - server listening on { url: 'http://localhost:4004' }
[cds] - server v10.1.0 launched in 560 ms

On Node.js 22 you may also see ExperimentalWarning: SQLite is an experimental feature. It is harmless here.

  1. Open http://localhost:4004/odata/v4/orders/BlockedOrders in your browser. You see the three orders as JSON. Then try a filter: http://localhost:4004/odata/v4/orders/BlockedOrders?$filter=currency%20eq%20'EUR'.

What success looks like (the filtered call):

{"@odata.context":"$metadata#BlockedOrders","value":[{"salesOrder":"4711","customer":"Made-up Retail GmbH","reason":"Credit limit exceeded","netValue":"12500.00","currency":"EUR"}]}

A filter that matches nothing returns "value":[]. That is a valid empty result, not an error.

  1. Press Ctrl+C to stop it, then go back to the course folder:

    • Windows (PowerShell):

      cd ..\..
    • macOS / Linux:

      cd ../..

What each file does:

File What it does
db/schema.cds Declares the BlockedOrders entity (a table) in the course namespace, with a key and four fields
db/data/course-BlockedOrders.csv Sample rows CAP loads into the database at start; the name ties it to the entity
srv/service.cds Exposes the entity as a read-only service; CAP serves OrdersService at /odata/v4/orders
cds watch Finds the files, creates an in-memory database, loads the CSV and serves OData

Notice the difference from Step 6. FastAPI gave you full control and you wrote every endpoint. CAP gave you a standard OData service, with filtering, from a data model. "CAP and side-by-side extensions for AI", later in this unit, builds on this.

Step 8: Run the Unit 6 check

  1. In the course folder (not in unit06), create check_unit06.py, paste the code below and save. It uses only built-in Python, like the earlier checks.
"""Check that your computer is ready for Unit 6 (AI applications: a Python API, CAP and Cloud Foundry).

Run it from your course folder:  python check_unit06.py
It uses built-in Python only. It asks node, npm, cds and cf for their versions, and asks cf which
org and space you are logged in to. It changes nothing and never prints passwords or tokens.
"""
import importlib.metadata
import importlib.util
import os
import re
import shutil
import subprocess
import sys

problems = 0


def report(ok: bool, label: str, fix: str = "", optional: bool = False) -> None:
    """Print one line: OK, MISSING (must fix) or LATER (optional for now)."""
    global problems
    if ok:
        print(f"  OK       {label}")
    elif optional:
        print(f"  LATER    {label}  ->  {fix}")
    else:
        problems += 1
        print(f"  MISSING  {label}  ->  {fix}")


def run(tool: str, *args: str):
    """Run a command-line tool and return (exit code, output), or (None, "") if it isn't installed."""
    path = shutil.which(tool)   # on Windows this also finds npm.cmd and cds.cmd
    if path is None:
        return None, ""
    try:
        done = subprocess.run([path, *args], capture_output=True, text=True, timeout=60,
                              env={**os.environ, "CF_COLOR": "false", "NO_COLOR": "1"})
    except (OSError, subprocess.TimeoutExpired) as error:
        return 1, str(error)
    return done.returncode, (done.stdout or "") + (done.stderr or "")


def first_version(text: str) -> str:
    """Find the first version number such as 24.21.0 in a tool's output."""
    match = re.search(r"(\d+)\.(\d+)\.(\d+)", text)
    return match.group(0) if match else ""


print("\n1. Python")
v = sys.version_info
report(v >= (3, 11), f"Python {v.major}.{v.minor}.{v.micro}",
       "the course needs Python 3.11 or newer (see Set up for Unit 2, Step 1)")
report(sys.prefix != sys.base_prefix, "virtual environment is active", "activate .venv (Step 1)")

print("\n2. Python libraries")
for module, package in [("fastapi", "fastapi"), ("uvicorn", "uvicorn"), ("dotenv", "python-dotenv")]:
    found = importlib.util.find_spec(module) is not None
    version = importlib.metadata.version(package) if found else ""
    report(found, f"{package} {version}".strip(), "pip install -r requirements.txt (Step 6)")

print("\n3. Node.js tools")
code, out = run("node", "--version")
node = first_version(out) if code == 0 else ""
major = int(node.split(".")[0]) if node else 0
report(major >= 22, f"Node.js {node or 'not found'}",
       "install the Node.js LTS from nodejs.org (Step 2); CAP needs version 22 or newer")
if 22 <= major < 24:
    print("           tip: CAP recommends Node.js 24; 22 works but is in maintenance")
code, out = run("npm", "--version")
report(code == 0, f"npm {first_version(out) if code == 0 else 'not found'}",
       "npm comes with Node.js; reinstall Node.js and open a new terminal (Step 2)")
code, out = run("cds", "--version")
match = re.search(r"@sap/cds-dk\D*?(\d+\.\d+\.\d+)", out) if code == 0 else None
report(bool(match), f"CAP development kit (@sap/cds-dk) {match.group(1) if match else 'not found'}",
       "npm add -g @sap/cds-dk, then open a new terminal (Step 3)")

print("\n4. Cloud Foundry")
code, out = run("cf", "version")
cf = first_version(out) if code == 0 else ""
report(cf.startswith("8."), f"cf CLI {cf or 'not found'}", "install the cf CLI v8 (Step 4)")
if cf:
    code, out = run("cf", "target")
    fields = {}
    for line in out.splitlines():
        if ":" in line:
            name, value = line.split(":", 1)
            fields[name.strip().lower()] = value.strip()
    org, space = fields.get("org", ""), fields.get("space", "")
    report(code == 0 and bool(org), f"logged in to org '{org}', space '{space}'" if org else "logged in to SAP BTP",
           "cf login -a <your API endpoint> (Step 5); needed only for the deployment topic", optional=True)

print("\n5. Course folder")
for path, step in [("unit06", "6"), (os.path.join("unit06", "hello_api.py"), "6"),
                   (os.path.join("unit06", "hello-cap", "db", "schema.cds"), "7"),
                   (os.path.join("unit06", "hello-cap", "srv", "service.cds"), "7")]:
    report(os.path.exists(path), path, f"create it (Step {step})", optional=True)

print()
if problems:
    print(f"{problems} item(s) to fix. Fix them in order, then run this again.")
    sys.exit(1)
print("All set. Your computer is ready for Unit 6. Log in with cf (Step 5) before the deployment topic.")
  1. Run it:

    python check_unit06.py

What success looks like (from our test, with a stand-in for a logged-in cf; your versions will differ):

1. Python
  OK       Python 3.13.15
  OK       virtual environment is active

2. Python libraries
  OK       fastapi 0.142.2
  OK       uvicorn 0.54.0
  OK       python-dotenv 1.2.4

3. Node.js tools
  OK       Node.js 22.22.0
           tip: CAP recommends Node.js 24; 22 works but is in maintenance
  OK       npm 10.9.4
  OK       CAP development kit (@sap/cds-dk) 10.1.0

4. Cloud Foundry
  OK       cf CLI 8.18.4
  OK       logged in to org 'a1b2c3d4trial', space 'dev'

5. Course folder
  OK       unit06
  OK       unit06/hello_api.py
  OK       unit06/hello-cap/db/schema.cds
  OK       unit06/hello-cap/srv/service.cds

All set. Your computer is ready for Unit 6. Log in with cf (Step 5) before the deployment topic.

On Node.js 24 the tip line doesn't appear. Without a BTP login, section 4 shows LATER logged in to SAP BTP and the check still ends with All set. That is a valid result: you only need the login for the deployment topic. Any MISSING line ends with item(s) to fix and must be fixed first.

What each part of the check does:

Part What it checks
run() Finds a tool on your PATH (including npm.cmd and cds.cmd on Windows), runs it and captures its output
Python Version 3.11 or newer, and that .venv is active
Python libraries That fastapi, uvicorn and python-dotenv are installed
Node.js tools Node.js 22 or newer, npm, and the version of @sap/cds-dk from cds --version
Cloud Foundry cf version 8, then cf target to read your org and space; not logged in is LATER, not an error
Course folder That the Step 6 and Step 7 files exist

Step 9: Save your work in Git

  1. Check what Git sees:

    git status

    You should see requirements.txt, check_unit06.py and unit06/. You must not see .env or a .cf folder. CAP's own .gitignore keeps node_modules out.

  2. Save:

    git add requirements.txt check_unit06.py unit06
    git commit -m "Set up Unit 6: Node.js, CAP, cf CLI and FastAPI"

If something goes wrong

What you see What it means What to do
python is not recognized, or command not found Python isn't installed, or the terminal can't find it Windows: repeat Unit 1, Step 1, then open a new terminal. macOS/Linux: use python3 until .venv is active
node, npm, cds or cf is not recognized The terminal started before the install changed PATH Close the terminal, open a new one, turn on .venv and try again. On Windows, restart VS Code
ModuleNotFoundError: No module named 'fastapi' FastAPI isn't installed in the Python you're using Check for (.venv) in the prompt, then pip install -r requirements.txt
npm ERR! code EACCES on macOS/Linux npm can't write to the global folder Don't use sudo. Run npm config set prefix ~/.npm-global, add ~/.npm-global/bin to PATH in your shell profile, open a new terminal and repeat Step 3
Windows: npm.ps1 or Activate.ps1 cannot be loaded PowerShell blocks scripts Run Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser, answer Y, and try again
npm ERR! network, ETIMEDOUT or self-signed certificate A company proxy or firewall blocks npm's registry Ask IT for the proxy settings, then npm config set proxy ... and npm config set https-proxy ...
Check shows MISSING Node.js 20... Node.js is too old for CAP 10 Install v24 (Step 2) and open a new terminal
cf login says credentials were rejected Wrong password, or the account uses two-factor or single sign-on Try once more, then use cf login -a ... --sso (Step 5)
cf login: Request error, Forbidden or timeout The endpoint is wrong, or the network blocks SAP's servers Copy the endpoint again from the cockpit; try another network, or ask IT to allow the BTP Cloud Foundry hosts
cf target says you are not logged in You haven't logged in yet, or the session expired Run cf login again (Step 5)
error while attempting to bind on address ... address already in use (or a message about the port being in use) Another program uses port 8000 (or 4004 for CAP) Stop the other program with Ctrl+C, or run python unit06/hello_api.py --port 8080
CAP: the log shows no serving OrdersService line, or the browser shows 404 cds watch ran in the wrong folder, or a .cds file name or path is wrong Run it from unit06/hello-cap; check srv/service.cds and db/schema.cds
CAP: "value":[] for every call The CSV wasn't loaded Check the name is exactly course-BlockedOrders.csv inside db/data
Windows: CAP stops with a SQLite error SQLite tools are missing Install them from sqlite.org (see the note in Step 3)

The SAP way: where these tools lead

The tools you installed are the same ones SAP's own guides use.

  • CAP is SAP's framework for business services on BTP. Its getting-started guide installs exactly what you installed: Node.js, @sap/cds-dk and the sapse.vscode-cds extension. It marks Java and Maven as optional.
  • Cloud Foundry in your trial runs apps you push with cf. SAP's trial documentation adds limits worth knowing now: apps stop automatically every day for cleanup and must be restarted, and the trial gives 4 GB of memory for applications.
  • SAP Business Application Studio is the browser alternative. You open it from the trial cockpit, and SAP's tutorial says it is available for US10 and AP21 trials. It is useful when a company laptop can't run installs.
Your laptop (this course) SAP Business Application Studio
Install effort This topic None; runs in the browser
Works offline Yes, except cf No
Python and FastAPI Yes Check your dev space's tools
Good for Learning, portfolio work in Git Locked-down laptops, team setups

Build vs. SAP: FastAPI or CAP?

Both APIs in this setup serve the same three orders. Use this to choose in later topics and on projects:

Question FastAPI (Python) CAP (Node.js)
Main job Custom endpoints, AI logic, model calls Business data and services in SAP's style
API style Whatever you design; JSON by default OData v4 by default, with filtering and paging built in
Code you write Every endpoint A CDS model; code only for custom logic
Fits SAP Fiori and SAP integration With extra work Designed for it
Python AI libraries Native Through a separate service or a JavaScript library
Typical use in this course The AI service (Building an AI API) The extension around it (CAP and side-by-side extensions)

A common shape on projects is both: a CAP service that owns the business data and calls a Python AI service for the model step.

Production concerns

  • Supported versions. Node.js 24 is LTS, and the Node.js project says production apps should use LTS releases only. CAP's release notes say Node.js 26 becomes Active LTS in October 2026. Plan upgrades; don't drift into them.
  • Pinned dependencies. requirements.txt here lists fastapi[standard] without a version, which is fine for learning. Real projects pin versions, and CAP projects commit package-lock.json.
  • Credentials. cf stores a sign-in token in .cf/config.json in your home folder. Never copy it into a project or share it. Run cf logout on shared machines.
  • No passwords in commands. The cf documentation warns against -p. In automation, use a technical user and secrets from a secret store.
  • Local only. The FastAPI app listens on 127.0.0.1, so only your own computer can reach it. Keep it that way until Unit 10 covers running AI on BTP in production.
  • Trial limits. Daily app stops, memory limits, and no production or team use. Pilots need a proper account.

Pitfalls

  • Forgetting to open a new terminal. Installers change PATH; old terminals don't see it.
  • Installing the newest Node.js "Current" line. Use the LTS line CAP recommends.
  • Using sudo npm. It causes permission problems later. Fix the npm prefix instead.
  • Running cds watch from the course folder. Run it inside unit06/hello-cap.
  • Misnaming the CSV file. CAP silently loads nothing if the name doesn't match <namespace>-<Entity>.csv.
  • Typing a password after -p. It ends up in your shell history.
  • Leaving the API running and wondering why the terminal ignores you. A server keeps the terminal busy; use a second one, and Ctrl+C to stop.

Exercise: add an order to both APIs and record your toolchain

  1. Run python check_unit06.py and copy its output.

  2. In unit06, create toolchain_notes.md with these lines and fill them in:

    # My Unit 6 toolchain
    
    - Node.js version:
    - npm version:
    - @sap/cds-dk version:
    - cf CLI version:
    - FastAPI version:
    - BTP login (org / space, or "not yet"):
    - One difference I noticed between the FastAPI and CAP versions:
  3. Add a fourth made-up order, 4714, to both APIs: as a new entry in BLOCKED_ORDERS in hello_api.py, and as a new line in course-BlockedOrders.csv. Use the reason Incomplete delivery address.

  4. Start the FastAPI app and call /explain with 4714. Stop it.

  5. Start cds watch in unit06/hello-cap and open http://localhost:4004/odata/v4/orders/BlockedOrders?$filter=salesOrder%20eq%20'4714'. Stop it.

  6. Commit unit06 with Git.

Done when: check_unit06.py ends with All set, both APIs return order 4714, and toolchain_notes.md is committed with every line filled in. The FastAPI app is the starting point for the next topic, Building an AI API.

Check yourself

Pick one answer for each question. The explanation appears after you choose.
  1. 1Why does the course install the CAP kit with npm add -g?

    Answer: B. @sap/cds-dk gives you the cds command, which you run in any folder. Libraries one project needs are installed locally in that project's node_modules instead.
  2. 2You installed Node.js, but node is "not recognized" in VS Code's terminal. What is the likeliest fix?

    Answer: C. Installers add their folder to PATH, but a terminal reads PATH only when it starts. Opening a new terminal, or restarting VS Code on Windows, picks up the change.
  3. 3How does CAP know to load course-BlockedOrders.csv into the BlockedOrders table?

    Answer: D. CAP matches the file name to the namespace and entity in the model. A wrong name means nothing is loaded, which shows up as an empty "value":[] result.
  4. 4The FastAPI /explain endpoint receives {"order": "4711"}. What happens?

    Answer: B. The Pydantic model ExplainRequest declares a required sales_order field. FastAPI checks the body against it and rejects a request without it before your function runs.
  5. 5cf login refuses your password, but it works in the BTP cockpit. What do you try next?

    Answer: C. Accounts with two-factor sign-in or single sign-on can't log in with a password at the prompt. --sso gives a web address where you sign in and get a one-time code. Passing a password with -p is discouraged.
  6. 6Where does cf keep your session after login, and why does it matter?

    Answer: D. cf saves the session, including a sign-in token, in its config file in your home folder. Anyone with that file can act as you until the token expires, so never copy or share it.
  7. 7The check shows LATER logged in to SAP BTP. Is the setup finished?

    Answer: A. Only MISSING lines make the check fail. Not being logged in is marked LATER because only the deployment topic pushes apps to Cloud Foundry.
  8. 8A team must expose AI-written explanations of blocked orders to an SAP Fiori app. Which shape fits best?

    Answer: C. CAP is designed for SAP-style services and Fiori, while Python suits the AI logic. Combining them lets each tool do the part it is built for.

Sources

Sign in to track your progress

We'll email you a one-time sign-in link. No password needed.

or

Tell us a little about you

Optional, every field. It helps us pitch answers to your questions at the right level and decide which topics to write next. It is never shown publicly, and you can change or clear it anytime from the account menu.

SAP areas you work in