SAP-samples/cloud-cap-hana-swapi
A CAP data model demonstrating bi-directional, many-to-many relationships, built on the SWAPI Star Wars dataset extended with TV shows and streaming series and loadable into SQLite, HANA or PostgreSQL.
Many-to-many relationships across a non-trivial dataset are hard to model well, and this rebuilds the old SWAPI Star Wars dataset as a CAP data model to practise it: people, films, species, starships, vehicles and planets, each linked in both directions. It extends the original with a Show entity for TV and streaming productions, an Episode composition beneath each show, and six read-only UNION ALL views that unify films and shows behind one query surface. The data comes from a two-step pipeline — a rate-limited Wookieepedia scraper with a committed cache, then a load step into SQLite, HANA or PostgreSQLPostgreSQLA relational database. For CAP it is the production database when the answer is not HANA, reached through an adapter that translates CDS queries into its SQL. — so the model can be explored without live scraping. It stops at the data layer and a generated Fiori preview UI; there is no bespoke application on top.
Facts
Where it sits
Who is behind it
In the atlas: maintains 222@SAP-samplesmaintainerAjinkya PatilContributes to this
In the atlas: contributes to 112@ajinkyapatil8190Brian BernardContributes to this
In the atlas: contributes to 64@btbernardThomas JungContributes to this
Developer Advocate
In the atlas: contributes to 15, wrote 6@jung-thomasMarian ZeisContributes to this
In the atlas: maintains 35, contributes to 86, wrote 25@marianfooPatrice BenderContributes to this
In the atlas: contributes to 11@patricebender5 contributors
What it declares
Every artifact
- Type
- Sample
- Origin
- By SAP
As a sample
- Form
- does not say
Connections
Defining entities, their relations and the views services consume
Download
Architecture
as cap/mta.yaml states it at 913fbde, readDownload
Bound, and not drawn
- cap-hana-swapi-srvhana, starwars-auditlog-service, SAP Application Logging service for SAP BTP, SAP Destination service, Event Mesh
- cap-hana-swapi-dbhana
- notification-content-deploymentSAP Destination service
Documented, with no instance in the document
- @cap-js/ai requires SAP AI Corecap-hana-swapi-srvconditionalThe service binding the recommendations need in a production deployment; without one, local development uses a mock implementation for UI smoke tests.cap-js/ai — README, Recommendations
A production deployment requires an [SAP AI Core](https://help.sap.com/docs/sap-ai-core) service binding. Without one, local development uses a mock implementation for UI smoke tests.
- @cap-js/hana requires SAP HANA Cloudcap-hana-swapi-srvconditionalThe database this is the service for: capire's standard database for production, reached with the credentials
cds watchorcds runfetch from the binding at runtime.Using SAP HANA Cloud for Production — capire, Prepare for ProductionThis configures deployment for SAP HANA. The configuration is added to a `[hybrid]` profile in your _package.json_.
Using SAP HANA Cloud for Production — capire, cds deployWith this information, `cds watch`/`run` can fetch the SAP HANA credentials at runtime, so that the server can connect to it.
Databases — capire, overview (the 2 is the page's footnote mark)in production, SAP HANA 2 is used by default
- @cap-js/postgres requires PostgreSQLcap-hana-swapi-srv
- @cap-js/ai requires SAP AI Corenotification-content-deploymentconditionalThe service binding the recommendations need in a production deployment; without one, local development uses a mock implementation for UI smoke tests.cap-js/ai — README, Recommendations
A production deployment requires an [SAP AI Core](https://help.sap.com/docs/sap-ai-core) service binding. Without one, local development uses a mock implementation for UI smoke tests.
- @cap-js/hana requires SAP HANA Cloudnotification-content-deploymentconditionalThe database this is the service for: capire's standard database for production, reached with the credentials
cds watchorcds runfetch from the binding at runtime.Using SAP HANA Cloud for Production — capire, Prepare for ProductionThis configures deployment for SAP HANA. The configuration is added to a `[hybrid]` profile in your _package.json_.
Using SAP HANA Cloud for Production — capire, cds deployWith this information, `cds watch`/`run` can fetch the SAP HANA credentials at runtime, so that the server can connect to it.
Databases — capire, overview (the 2 is the page's footnote mark)in production, SAP HANA 2 is used by default
- @cap-js/postgres requires PostgreSQLnotification-content-deployment
Bound in the descriptor, not joined to an entry
hana
README
quoted from SAP-samples/cloud-cap-hana-swapi under Apache-2.0, readcloud-cap-hana-swapi - bi-directional, many-to-many SAP Cloud Application Programming Model example
Description
SWAPI - the Star Wars API. This sample is based upon the sample at swapi.dev which in turn was based upon swapi.co. The original source can be found at https://github.com/Juriy/swapi.
The original project was a data set and data model based in Python that exposed data from the Star Wars movies sourced originally from the community wiki: Wookiepedia. It encompasses data about the People, Films, Species, Starships, Vehicles and Planets from Star Wars.
The projects described above have fallen out of maintenance but still offered the opportunity for a fun yet challenging learning experience from a non-trivial data model. The many bi-directional, many-to-many relationships with the data provides a good basis for an SAP Cloud Application Programming Model and Fiori Draft UI sample.
This project extends the original data set with TV Shows and streaming series (The Mandalorian, The Clone Wars, Andor, etc.) scraped live from Wookieepedia, and introduces unified Media views that query across both films and shows.
Data Model
Films

Shows (TV Series & Streaming)
The Show entity represents all canon Star Wars TV and streaming productions. It shares the same relationship structure as Film — each show can be linked to characters, planets, starships, vehicles, and species.
| Field | Type | Notes |
|---|---|---|
title | String | @mandatory |
show_type | Enum | LIVE_ACTION_SERIES, ANIMATED_SERIES, ANIMATED_FILM, ANTHOLOGY |
seasons | Integer | Number of seasons |
episode_count | Integer | Total episode count |
network | String | Broadcaster / streaming platform |
director | String | Lead director(s) |
producer | String | Lead producer(s) |
release_date | Date | First air date |
Each show owns a composition of Episode records (cascade-delete). The Episode entity captures per-episode metadata: season_number, episode_number, title, air_date, director, writer, runtime (minutes), and timeline (in-universe date, e.g. "19 BBY").
Junction tables: Show2People (physical), Episode2People, Episode2Planets, Episode2Starships, Episode2Vehicles, Episode2Species
Show2Planets, Show2Starships, Show2Vehicles, and Show2Species are CDS define view declarations that aggregate over the corresponding Episode2* tables. They are not physical tables — show-level relationship data is derived from episode-level scraping.
Unified Media Views
Six read-only UNION ALL views join Film and Show data across a single query surface. The relationship views each include a branch for Episode2* data so that episode-level associations are surfaced at the media level:
| View | Returns |
|---|---|
Media | All films and shows with a media_type discriminator ('FILM' / 'SHOW') |
MediaCharacters | All film+show+episode → character relationships |
MediaPlanets | All film+show+episode → planet relationships |
MediaSpecies | All film+show+episode → species relationships |
MediaStarships | All film+show+episode → starship relationships |
MediaVehicles | All film+show+episode → vehicle relationships |
People

Planets

Species

Starships

Vehicles

Requirements
Download and Installation
The rest of the operations can be performed within the cap folder and there are scripts in the package.json file for major operations.
You can use npm run build to perform the cds build and should be run before deployment to HANA or whenever you make changes to the data model.
You can run npm run hana to deploy the content to your HANA database. Just be sure from the terminal that you are logged into the cf/xs cli and targeting the Account/Org/Space where you want the content to live. By default this command will create an HDI Container instance named starwars. Note: due to some strange circumstances in the latest versions of CAP it seems the /gen/srv folder is getting cleared after any deployment to HANA. Therefore just execute a cds build or npm run build after any deployment to restore the /gen folder until we find the root cause of this issue.
Data Pipeline
Star Wars data is sourced from Wookieepedia via a rate-limited MediaWiki API scraper. The pipeline is two steps:
Step 1 — Scrape (optional — committed cache makes this instantaneous):
cd cap
npm run scrape # cache-first run — uses committed cache, completes in seconds
npm run scrape:films # films-only run (no episodes); reproduces the original SWAPI dataset
npm run scrape:bypass-cache # fetch fresh data from Wookieepedia (prompts for confirmation)
The scraper crawls three levels deep: Show page → Season page → Episode page. It writes nine JSON files to scripts/data/raw/:
films.json, shows.json, episodes.json, people.json, planets.json, species.json, starships.json, vehicles.json, relationships.json
Cache files (scripts/data/cache/) are committed to the repository (~6,469 files), so clones can run npm run scrape without any network access. Use --bypass-cache only when you need genuinely fresh Wookieepedia data.
Step 2 — Load into your target database:
npm run load_sqlite # SQLite (local development)
npm run load # SAP HANA Cloud (hybrid profile — requires .cdsrc-private.json)
npm run load_pg # PostgreSQL
The loading script is convertData.js. It reads the raw JSON files and upserts all entities and junction records using CAP CQL.
Scraped data included:
- 11 canon films — Episodes I–IX, Rogue One, Solo (with directors, producers, release dates)
- 15 shows — 8 live-action series + 6 animated series (The Mandalorian, The Clone Wars, Andor, Rebels, etc.)
- 772 episodes — per-episode metadata and entity relationships (characters, planets, starships, vehicles, species)
The command npm start or cds run will start the service running locally. It will open the standard CAP test page where you can explore the OData Services or the Fiori UI.
From the Cloud Application Programming Model preview (which opens locally when using npm start or cds run), you can access the Swagger UI test tool (with entity diagrams), test the OData services or metadata calls directly in the browser, or access the Fiori preview UI for each of the main entities.



Upgrade Notes
- Breaking change: legacy value-help helper endpoints were removed in favor of
*Valuesentities. - Migration details and endpoint mapping are documented in:
Known Issues
If you receive an error like the following when running the convertData script
[Error: SQLITE_BUSY: database is locked] {
errno: 5,
code: 'SQLITE_BUSY',
query: 'DELETE FROM star_wars_People'
}
This is caused by the parallel nature of the loading of the data in SQLite. The default script with its parallel loading works fine when you use HANA as the target persistence. However if you are using SQLite for your tempoary testing persistence, then you can use the alternative convertDataLite script instead.
Note: due to some strange circumstances in the latest versions of CAP it seems the /gen/srv folder is getting cleared after any deployment to HANA. Therefore just execute a cds build or npm run build after any deployment to restore the /gen folder until we find the root cause of this issue.
How to obtain support
This project is provided "as-is": there is no guarantee that raised issues will be answered or addressed in future releases.
License
Copyright (c) 2024 SAP SE or an SAP affiliate company. All rights reserved. This project is licensed under the Apache Software License, version 2.0 except as noted otherwise in the LICENSE file.
Star Wars and all associated names are copyright Lucasfilm ltd. All data in this sample has been freely collected from open sources such as Wookiepedia under CC-BY-SA .
History
Other 11
Notes
Changed
- Upgrade to SAP CAP 10: @sap/cds from 9.9.1 to 10.0.3 (@sap/cds-compiler 7.0.1)
- Update @cap-js/sqlite from 2.x to 3.0.2, @cap-js/hana from 2.x to 3.0.1, @cap-js/postgres from 2.x to 3.0.1 (CAP 10 driver majors)
- Update @cap-js/telemetry from 1.x to 2.0.1
- Update @cap-js/change-tracking to 2.0.2, @cap-js-community/odata-v2-adapter to 1.16.0, @cap-js/ord to 1.9.1, @sap/cds-common-content to 3.2.0
- Update eslint to 10.7.0 and @sap/dev-cap-tools to 1.53.4
- Remove CAP 10-obsolete feature flags from .cdsrc.json (ieee754compatible, consistent_params, compat_srv_getters, compat_texts_entities, compat_assert_not_null, compat_save_drafts, calc_elements) — now defaults or removed in CAP 10
- Simplify cds.requires.queue to
true(legacyLocking flag obsolete in CAP 10) - Scraper: replace axios with Node.js native fetch in mediawiki.js, preserving throttle, 15s AbortController timeout, and 429/503 retry/backoff — removes axios and unused uuid dependency (clears 10 Dependabot alerts, npm audit reports 0 vulnerabilities)
Fixed
- Scraper normalizeDate returned a date one day early in any timezone ahead of UTC — locale date strings (e.g. "May 25, 1977") parsed as local midnight but were formatted via toISOString(); now formatted from the matching parse frame, verified timezone-independent from UTC-12 to UTC+14
- Scraper extractor test fixtures updated to the {{App}} (films) and {{Credits}} (shows) template formats the extractors actually read, and a stale normalizeInteger ordinal-word assertion corrected — full scraper suite now 87/87 passing
Removed
- Empty 0-byte cap/db/src/TEST.hdbcalculationview scratch file that caused HANA HDI deployment to fail with an XML parse error
Other 19
Notes
Changed
- Update @sap/cds from 9.8.5 to 9.9.1
- Update @cap-js/cds-test from 0.4.1 to 1.0.1 (stable release)
- Update eslint from 10.2.1 to 10.3.0
- Update @cap-js/hana from 2.7.0 to 2.8.0
- Update @cap-js/sqlite from 2.2.0 to 2.4.0
- Update @cap-js/postgres from 2.2.0 to 2.3.0
- Update @sap/cds-common-content from 3.1.0 to 3.2.0
- Update @sap/dev-cap-tools from 1.53.2 to 1.53.3
- Update @cap-js/change-tracking from 1.2.1 to 2.0.0-beta.11 (trigger-based architecture with ~2.4-50x performance improvement)
- Update site dependencies (mermaid 11.13→11.14, vue 3.5.31→3.5.33)
- Update scraper dependencies (axios 1.14→1.15)
- Raise minimum Node.js version from 20 to 22 (CDS 10 requirement)
- Enable CDS 10 forward-compatibility flags: ieee754compatible, consistent_params, compat_srv_getters, compat_texts_entities, compat_assert_not_null, compat_save_drafts, calc_elements
- Disable legacy queue locking (queue.legacyLocking: false) in preparation for CDS 10
- Add HANA migration table (sap.changelog.Changes.hdbmigrationtable) for change-tracking v2 schema migration
- Enable native node:sqlite driver (driver: "node") — uses Node.js built-in SQLite instead of better-sqlite3
- Enable parallel $batch GET processing (max_batch_parallelization: 3) for concurrent read-only batch atomicity groups
Added
- cds-test-v1.test.js — showcase test demonstrating @cap-js/cds-test v1.0 features: Chai assertions, Fetch-based HTTP shortcuts, native sqlite verification
- @cap-js/ord plugin (v1.6.0) — exposes Open Resource Discovery endpoints (/.well-known/open-resource-discovery, /ord/v1/documents/ord-document) for machine-readable application metadata
Other 49
Notes
Added
- Episode entity and Episode2* junction tables (Episode2People, Episode2Planets, Episode2Starships, Episode2Vehicles, Episode2Species) as compositions of Show
- StarWarsEpisode service exposing Episode and Episode2* projections as read-only
- Show2Planets, Show2Starships, Show2Vehicles, Show2Species replaced by CDS derived views aggregating over Episode2* tables
- Wookieepedia scraper pipeline: rate-limited MediaWiki API client, disk cache, entity/episode/season extractors, orchestrator, and CLI
- Full scrape of 11 films and 15 shows with 772 episodes and episode relationships from Wookieepedia
- Episode data fields: director, writer, season_number, episode_number, air_date, opening_crawl, show title association
- Clone Wars chronological episode ordering in StarWarsEpisode service
- Opening crawl texts for main Star Wars saga films
- Film.episode_id populated from roman numeral in Wookieepedia page title
- Sub-series pages (e.g. Tales anthology) registered as shows and their episodes correctly attributed
- Second-pass entity scrape to resolve entities discovered via episode back-references
- Virtual edit_url field on Media projection in StarWarsShow service, computed by handler
- Star Wars Media Browser Fiori webapp (list report + object page)
- Star Wars Films Fiori webapp (list report + object page)
- Star Wars Shows Fiori webapp with Episodes sub-navigation tab
- Fiori launchpad page with People, Films, and Shows tiles
- i18n labels and value helps for Media entity type selection fields
- Fiori annotations for Media list report and object page
- VitePress documentation site with animated Star Wars opening crawl homepage, Imperial Dark and Jedi Archives CSS themes, CDS syntax highlighting, and GitHub Pages CI deployment
- MIDI audio (Imperial March, Jedi Theme) and hexagon SVG logos for VitePress themes
- VitePress Apps section with per-app documentation pages (People, Media Browser, Film editor, Show/Episode editor) and API overview page
- Shows & Episodes section in VitePress API sidebar with architecture deep-dive
- Generated @cds-models type definitions for all services (DataService, StarWarsEpisode, StarWarsFilm, StarWarsPeople, StarWarsPlanet, StarWarsShow, StarWarsSpecies, StarWarsStarship, StarWarsVehicle)
- readme.mjs custom widdershins wrapper with circular $ref handling to prevent stack overflow during OpenAPI→Markdown generation
- Generated OpenAPI 3.0 specifications for all services (OData v4 and REST variants)
- Viewer app Galaxy/Light CSS themes with responsive layout, sort, filter, column-level search, and pagination
- Viewer app detail panel with field-by-field display and keyboard navigation (arrow keys, Escape)
- Viewer app row selection with clipboard copy (Tab-delimited), persisted rowKey cleared on entity switch or panel dismiss
- jsconfig.json for CAP service layer IDE support
- CAP Cheat Sheet expanded with detailed CDS modeling patterns, handler registration, and common pitfalls
Changed
- convertData.js rewritten to load flat JSON from scripts/data/raw instead of Django fixtures, with parallel chunk loading and SQLite-safe sequencing
- Episode loading added to data pipeline; Show2* physical table inserts removed (now derived views)
- Scraper: episode titles extracted from table rows (not all section wikilinks); season links scoped to level-2/3 headings; show attribution uses episode infobox series field filtered by show title
- Episode.director and Episode.writer use unbounded String (no length limit)
- normalizeInteger extended to parse ordinal words (One, Two, …) for season_number
- Migration handling updated and Episode Fiori annotations improved
- VitePress copy-content pipeline updated to support Fiori app docs, API restructure, and front-matter title extraction
- VitePress nav/sidebar restructured: added Apps section, split API into per-service pages, added Shows & Episodes
- CI docs workflow now also triggers on cap/README.md changes
- Viewer app index.html rewritten with SRI hashes on all CDN resources, Content-Security-Policy meta tag, and viewport meta
- README updated with current project structure, Fiori app descriptions, and revised pitfalls section
Fixed
- Cross-show episode attribution prevented by filtering extractSeasonLinks to the current show title
- Anthology shows (Tales) without season sub-pages now extract episodes directly from the show page
- Piped wikilinks in episode infobox now yield the series page title, not the display label
- Sub-series character relationships accumulated correctly when registering as a show
- Data quality fixes for sequel trilogy character/planet relationships
- Obsolete hand-written TypeScript type definitions (cap/types/) replaced by generated @cds-models artifacts
- Viewer CSP extended with unsafe-eval to allow Vue 3 runtime template compiler
- Viewer pagination handles backend returning @odata.count=0 without breaking page calculation
Breaking 1, Other 9
Notes
Changed
- Enhance README and improve project documentation
- Add PostgreSQL profile-specific model exposure updates across CDS models and service projection
- Add and expand Star Wars CDS model unit tests, including profile-specific exposure coverage
- Update project dependencies and bump version to 1.8.0
- Update dev container setup (Dockerfile and devcontainer.json) for Node.js LTS and Cloud Foundry CLI installation
- Add CAP modeling and handler guidelines plus validation prompt workflows
- Add compatibility-safe value-help entity migration (*Values helper entities) while retaining legacy helper entities/projections with deprecation comments
- BREAKING: remove legacy value-help helper entities/projections (climate, terrain, hair_colors, eye_colors, skin_colors, classification, designation, language) in favor of *Values artifacts
- Migration details: cap/docs/value-help-migration.md
Other 3
Notes
Changed
- CAP version 8.0
- Update for SAPUI5 1.126.0
- If you have ran this project locally previously, I recommend deleting your node_modules folder and doing a clean install of all dependencies
Other 7
Notes
Changed
- CAP version 7.4.0
- CAP version 7.5.0
- Add Audit Logging functionality - added to People entity in schema.cds
- Add Notifications - emit alert upon change/update/create of People entity - see people-service.js
- Add Change Tracking - see change-tracking.cds for annotations adding tacking to the People entity
- Add Persistent Outbox
- Update for SAPUI5 1.120
Other 2
Notes
Changed
- Add support for new sqlite database service
- Add support for new postgres database service
Other 2
Notes
Changed
- SAP CAP updated to 7.0 June 2023 Rel - Major Annual Update
- SAPUI5 update to 1.115.0
Other 3
Notes
Changed
- SAP CAP updated to 6.6 Feb 2023 Rel
- Fixes in the convertData to avoid issues with parallelization and DB constrains
- SAPUI5 update to 1.111.0
Other 3
Notes
Changed
- SAP CAP updated to 6.3
- SAPUI5 update to 1.108.2
- New Node.js minimal version is 14.18
Other 3
Notes
Changed
- SAP CAP updated to 6.3
- SAPUI5 update to 1.108.2
- New Node.js minimal version is 14.18
Other 6
Notes
Changed
- SAP CAP updated to 6.1
- SAPUI5 update to 1.105.0
- Kyma Helm Charts updated for new functionality in CAP 6.1
Added
- Update to SAP Cloud Application Programming Model 6.0.x - Yearly Major Release
- Add Support for Node.js 18.x
- Added Helm Charts support for deployment on Kyma/K8S
Other 6
Notes
Changed
- GraphQL support is now GA by switching to the @sap/cds-graphql dependency. Removal of old GraphQL dependencies.
- Remove Support Node.js 12.x, minimal version now 14.15 as enforced by @sap/cds itself
- SAPUI5 update to 1.103.0
Added
- Update to SAP Cloud Application Programming Model 6.0.x - Yearly Major Release
- Add Support for Node.js 18.x
- Added Helm Charts support for deployment on Kyma/K8S
Other 2
Notes
Changed
- Dark Theme loading optimization thanks to Marian Zeis PR #4
Added
- Added async bootstrap for UI5 in preparation for Patch-Level Independent Bootstrap - although I couldn't switch yet as it doesn't seem to work for version 1.100
Other 8
Notes
Changed
- Update to CAP March 2022 5.9
- Update to SAPUI5 1.100
- Reactivated experimental GraphQL support. Use from test application with /graphql
- People App now uses OS setting and adjusts to dark theme - new sap_horizon_dark
Added
- New Changelog - You are looking at it
- Database Integrity Constraints
- People Entity Name Attribute Fuzzy Search via Native Database Clauses
- New tallestPerson view uses Native HANA Functions with non-standard syntax
Details
Sources
Sources are graph entities: the same page may back several entries, and an unreachable source flags every row that rests on it.
Compatibility and provenance
Flavors
“[Node.js 16, 18, or 20](https://nodejs.org/en/)” — SAP-samples/cloud-cap-hana-swapi — README
History in the atlas
- First seen.
For your agent
- Ref
artifact:sap-samples-cloud-cap-hana-swapi- JSON
- /artifacts/sap-samples-cloud-cap-hana-swapi.json
- MCP
- Connecting an agent