The SAP Cloud Application Programming Model is an open and opinionated, framework of languages, libraries, and tools for building enterprise-grade services and applications. It guides developers through proven best practices and a great wealth of out-of-the-box solutions for recurring tasks.
CAP-based projects benefit from a primary focus on the domain. Instead of delving into overly technical disciplines, we focus on accelerated development and safeguarding investments in a world of rapidly changing cloud technologies.
CAP features a mix of broadly adopted open-source and SAP technologies. The major building blocks are highlighted in the figure.
Core Data Services (CDS)
CDS is a family of domain-specific languages (CDL, CQL) and corresponding notations (CSN, CQN, CXN). It serves as our ubiquitous modeling language, for example, for capturing domain models and service definitions in a conceptual way, and as such is the very backbone of CAP.
These are libraries for Java and Node.js to provide and consume services through synchronous as well as asynchronous APIs. Based on ubiquitous notions of events and queries, they allow implementing services in protocol-agnostic and platform-agnostic ways.
The SDKs comprise out-of-the-box integration to lower-level platform feature services, such as authentication and credential flows, on/off-boarding of SaaS tenants, etc. All this is concealed behind higher-level abstractions to avoid hard-wiring. Yet all follow a white-box approach, allowing unrestricted access to native features of underlying technologies in case that is required.
Using CAP doesn’t require any specific editor or IDE. Everything can be done using the [
@sap/cds-dk] command line interface and any editor or IDE of your choice. However, dedicated support for CAP is available through SAP Business Application Studio as well as through plugins for Visual Studio Code and Eclipse, including textual and graphical editors.
Following are the key design principles realized in CAP.
Open & Opinionated
It sounds like a contradiction, but it isn’t: While CAP certainly gives opinionated guidance with many out-of-the-box solutions for recurring tasks, we don’t sacrifice openness and flexibility. This means that you stay in control of which technologies to choose, which architecture patterns to follow, or which parts of CAP to actually use.
CAP provides out-of-the-box support for SAP Fiori and SAP HANA, but that doesn’t lock you in to these choices. You can always combine CAP-based services with alternative UI or database technologies. CAP’s core components are explicitly designed for you to integrate with alternatives.
CAP doesn’t presume overarching architectures or methodologies. For example, it’s your choice whether to build a classic CRUD application or whether to adopt CQRS or Event Sourcing, while CAP merely tries to get the tedious boilerplate out of your way.
Keeping pace with rapidly changing cloud technologies is a major challenge when you have to hardwire too many things to today’s technologies, which might soon be obsolete. CAP provides out-of-the-box integration with many essential platform services, concealed behind higher-level APIs, which greatly helps avoid lock ins and safeguards your investments.
The core concepts of CAP, as briefly introduced in the sections below, are:
- Domain Models — to capture the static aspects of your problem domain
- Aspects — for clean models, separation of concerns, verticalization, extensibility
- Services — to capture behavioral aspects; every active thing in CAP is a service
- Events — blurring the line between synchronous and asynchronous APIs
- Queries — as the ubiquitous key ingredient for serving requests automatically
- Protocols, APIs — for providing and consuming services in a protocol-agnostic way
- The CAP Paradigm — summarizing everything and putting it in context
Anatomy and Overview
The figure illustrates the anatomy of a typical CAP-based application, highlighting the core concepts.
Domain Models capture the static aspects of a problem domain as entity-relationship models. With entities and associations, CDS provides a language that is close to the conceptual thinking of domain experts. Compositions enhance this to document structures. Moreover, aspects allow you to keep domain models clean, concise, and **comprehensible by factoring out technical concerns.
CDS’s aspects allow you to flexibly extend definitions with new elements as well as to override properties. This can happen in the same or separate files or projects, and greatly promotes both, separation of concerns as well as extensibility, for example in verticalization and customization scenarios.
Every active thing in CAP is a service, including local or remote things, even databases. In this way, services embody the behavioral aspects of a domain and act as facades to consumers. Service definitions are interpreted by generic providers at runtime to serve requests automatically. All services are configured, implemented, and consumed using the same uniform, protocol-agnostic APIs.
Everything that happens at runtime is in response to events. CAP features a ubiquitous notion of events, which represent both, requests coming in through synchronous APIs, as well as asynchronous event messages, thus blurring the line between both worlds. In both cases, custom logic can be provided through event handlers hooked in to respective service providers.
Each data access is expressed and processed through queries based on CQL (and CQN), which enhances SQL towards graphs and document structures. At design time, queries declare projections, that is views, on underlying entities. At runtime, queries are captured in first-class and first-order objects — that is, they can be passed to services for execution and stacked recursively as queries on queries. These powerful, intrinsic querying capabilities are key to serve requests automatically in generic handlers.
Services can be consumed (inbound) and can themselves consume other services (outbound) through various protocols. Currently supported protocols are OData, plain REST/HTTP, and AMQP. Converters are provided to translate CDS service definitions into corresponding OData EDMX V2 and V4, JSON Schema, OpenAPI, and AsyncAPI formats to publish APIs in those formats.
The CAP Paradigm
CAP is based on two major paradigms: First, the declarative paradigm, that is to capture knowledge about a problem domain declaratively as much as possible in order to automate many tasks in generic, broadly reused implementations. Second, a service-centric paradigm, based on ubiquitous notions and use of Services, Events and Queries.
- Models capture intent — to benefit from generic implementations
- Data is passive — that is, without its own behavior, adhering to REST
- Every active thing is a Service — acting as facades to access data
- Services are pure functions — that is, without their own state
- Services react on Events — featuring synchronous and asynchronous APIs
- Querying is key! — both, to express projections as well as to access data
CAP != ORM
Note that these principles are intentionally very much in contrast to frameworks applying forms of object-relational mapping, based on the notion of active objects modifying internal states, hence leading to side effects. Moreover, querying is in strong contrast to procedural and imperative approaches to access and process data, frequently found in several persistence frameworks.
Following are some best practices for working with CAP:
Focus on your Domain → “What, not how!”
CAP is based on a declarative paradigm, which is about placing a project’s primary focus on domain knowledge and intent, instead of imperative coding. CAP-based projects use CDS to capture static as well as behavioral aspects of a problem domain on conceptual levels, in concise, and comprehensible ways. This promotes close collaboration between developers and domain experts to gradually refine domain knowledge.
Evolutionary Development → “Grow-as-you-go…“
Following the principle of convention over configuration, there’s no need to set things up upfront. Instead, they can be added gradually over time, as needed. In addition, CAP provides lightweight stand-ins for essential platform features, which allow fast dev-test-run cycles with minimal complexity of developer landscapes by running lightweight, yet fully fledged servers. Later on, you move ahead to running your apps in close-to-productive setups for integration tests and delivery, without any change in models or code.
Generic Runtimes → “Turnkey Development”
Given the declarative information in models, CAP runtimes can quickly run a lightweight server in a jump-start fashion, as well as automate many tedious tasks, such as serving CRUD requests, validating input, etc. This minimizes boilerplate code you’d otherwise have to write. This not only speeds up development, but also increases quality as the generic implementation provides single points to fix and optimize as well as all the usual nonfunctional requirements, such as supportability, extensibility, etc.
Contracts First → Parallelizing Tasks
Because all you need to run a service is a service definition, projects containing UIs should start with the service definitions and then spawn two teams working in parallel, one working on the frontend, and the other on the backend. Both teams should use the service definitions as their interface contracts, collaborating in closed loops to refine them iteratively.
Agnostic Services → ‘Late-Cut Microservices’
CAP promotes a service-oriented paradigm with single-purposed services, which can later be deployed and run as separate microservices. However, you can always decide to run them embedded in a single-server process, avoiding the efforts and costs of microservice DevOps, at least in the early phases of development.