Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion guides/deploy/build.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ cds build --production
Build tasks are derived from the CDS configuration and project context. By default, CDS models are resolved from these sources:

- _db/_, _srv/_, _app/_ — default root folders of a CAP project
- _fts/_ and its subfolders when using [feature toggles](../extensibility/feature-toggles#enable-feature-toggles)
- _fts/_ and its subfolders when using [feature toggles](../extensibility/feature-toggles#enable-feature-toggles-in-node-js)
- CDS model folders and files defined by [required services](../../node.js/cds-env#services)
- Built-in examples: [Event Queues](../../node.js/event-queues#configuration) or [MTX-related services](../multitenancy/mtxs#mtx-services-reference)
- Explicit `src` folder configured in the build task
Expand Down
140 changes: 46 additions & 94 deletions guides/extensibility/feature-toggles.md
Original file line number Diff line number Diff line change
@@ -1,58 +1,48 @@
---
synopsis: >
Toggled features are pre-built extensions built by the provider of a SaaS application, which can be switched on selectively per subscriber.
impl-variants: true # to enable Node.js/Java toggle
---

# Feature Toggles

{{$frontmatter?.synopsis}}

<ImplVariantsHint />

## Introduction and Overview

CAP feature-toggled aspects allow SaaS providers to create pre-built features as CDS models, extending the base models with new fields, entities, as well as annotations for SAP Fiori UIs. These features can be assigned to individual SaaS customers (tenants), users, and requests and are then activated dynamically at runtime, as illustrated in the following figure.

![This graphic shows an inbound request passing authentication and then the CAP runtime queries the database as well as the model provider service to know which features belong to the inbound request.](./assets/feature-toggles.drawio.svg)

### Get `cloud-cap-samples-java` for step-by-step Exercises {.java}

The following steps will extend the [CAP samples for Java](https://github.com/SAP-samples/cloud-cap-samples-java) app to demonstrate how features can extend data models, services, as well as SAP Fiori UIs. If you want to exercise these steps, get [cloud-cap-samples-java](https://github.com/SAP-samples/cloud-cap-samples-java) before, and prepare to extend the *Fiori* app:
### Get Sample for Step-By-Step Exercises

<div class="impl java">
The following steps will extend the [CAP samples for Java](https://github.com/SAP-samples/cloud-cap-samples-java) / [cap/samples/bookstore](https://github.com/capire/bookstore) app to demonstrate how features can extend data models, services, as well as SAP Fiori UIs. If you want to exercise these steps, get [cloud-cap-samples-java](https://github.com/SAP-samples/cloud-cap-samples-java) before, and prepare to extend the *Fiori* (Java) / *bookstore* (Node.js) app:

```sh
::: code-group
```sh [Java]
git clone https://github.com/SAP-samples/cloud-cap-samples-java
cd cloud-cap-samples-java
mvn clean install
```

</div>

Now, open the app in your editor, for example, for VS Code type:

```sh
code .
```

### Get `cap/samples` for Step-By-Step Exercises {.node}

The following steps will extend the [cap/samples/bookstore](https://github.com/capire/bookstore) app to demonstrate how features can extend data models, services, as well as SAP Fiori UIs. If you want to exercise these steps, get [cap/samples](https://github.com/capire/samples) before, and prepare to extend the *bookstore* app:

```sh
```sh [Node.js]
git clone --recurse-submodules https://github.com/capire/samples
cd samples
npm install
```

Now, open the `bookstore` app in your editor, for example, by this if you're using VS Code on macOS:
:::

```sh
Now, open the app in your editor, for example, for VS Code type:

::: code-group
```sh [Java]
code .
```
```sh [Node.js]
code bookstore
```
:::

## Enable Feature Toggles {.node}
## Enable Feature Toggles in Node.js

### Add `@sap/cds-mtxs` Package Dependency

Expand Down Expand Up @@ -130,11 +120,10 @@ In principle, features can be toggled per request, per user, or per tenant; most

### In Development

<div class="impl node">
CAP Node.js' `mocked-auth` strategy has built-in support for toggling features per tenant, per user, or per request. CAP Java's [Mock User Authentication with Spring Boot](../../java/security#mock-users) allows to assign feature toggles to users based on the mock user configuration. To demonstrate toggling features per tenant, or user, you can add these lines of configuration to our `package.json` of the SAP Fiori app (Node.js) or to the mock user configuration in the `srv/src/main/resources/application.yaml` file (CAP Java).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@agoerler Is there meanwhile also the option to toggle by tenant in CAP Java? The current config doesn't show that.


CAP Node.js' `mocked-auth` strategy has built-in support for toggling features per tenant, per user, or per request. To demonstrate toggling features per tenant, or user, you can add these lines of configuration to our `package.json` of the SAP Fiori app:

```json
::: code-group
```json [Node.js: package.json]
{"cds":{
"requires": {
"auth": {
Expand All @@ -152,13 +141,7 @@ CAP Node.js' `mocked-auth` strategy has built-in support for toggling features p
}}
```

</div>

<div class="impl java">

CAP Java's [Mock User Authentication with Spring Boot](../../java/security#mock-users) allows to assign feature toggles to users based on the mock user configuration. To demonstrate toggling features per user, you can add these lines to the mock user configuration in the `srv/src/main/resources/application.yaml` file:

```yaml
```yaml [Java: application.yaml]
cds:
security.mock.users:
- name: carol
Expand All @@ -171,37 +154,33 @@ cds:
- name: fred
features:
```

</div>
:::

In effect of this, for the user `carol` the feature `isbn` is enabled, for `erin`, the features `isbn` and `reviews` are enabled, and for the user `fred` all features are disabled.

### In Production

<div class="impl node">

::: warning No features toggling for production yet
Note that the previous sample is only for demonstration purposes. As user and tenant management is outside of CAP's scope, there's no out-of-the-box feature toggles provider for production yet. → Learn more about that in the following section [*Feature Vector Providers*](#feature-vector-providers).
::: warning Bring your own toggle provider for production
Note that the previous sample is only for demonstration purposes. As user and tenant management is outside of CAP's scope, there's no out-of-the-box feature toggles provider for production yet. → Learn more about that in the following section [*Feature Vector Providers*](#feature-vector-providers-in-node-js).
:::

<div id="toggle-production-node-end" />

</div>

<div class="impl java">
#### In CAP Java

For productive use, the mock user configuration must not be used. The set of active features is determined per request by the [Feature Toggles Info Provider](../../java/reflection-api#feature-toggles-info-provider).
For productive use in CAP Java, the mock user configuration must not be used. The set of active features is determined per request by the [Feature Toggles Info Provider](../../java/reflection-api#feature-toggles-info-provider).

You can register a [Custom Implementation](../../java/reflection-api#custom-implementation) as a Spring bean that computes the active feature set based on the request's `UserInfo` and `ParameterInfo`.

<div id="toggle-production-java-end" />

</div>

## Test-Drive Locally {.node}
## Test-Drive Locally in Node.js

To test feature toggles, just run your CAP server as usual, then log on with different users, assigned to different tenants, to see the effects.

> [!INFO] Local test with CAP Java and sidecar
> How to test a CAP Java project locally is described in [Model Provider in Sidecar](#model-provider-in-sidecar).

### Run `cds watch`

Start the CAP server with `cds watch` as usual:
Expand All @@ -221,7 +200,7 @@ cds watch

> The `ModelProviderService` is used by the runtime to get feature-enhanced models.

### See Effects in SAP Fiori UIs {#test-fiori-node}
### See Effects in SAP Fiori UIs

To see the effects in the UIs open three anonymous browser windows, one for each user to log in, and:

Expand All @@ -238,15 +217,13 @@ For example the displayed UI should look like that for `erin`:

The `ModelProviderService`, which is used for toggling features, is implemented in Node.js only. To use it with CAP Java apps, you run it in a so-called *MTX sidecar*. For a CAP Node.js project, this service is always run embedded with the main application.

### Create Sidecar as Node.js Project
### Create Sidecar

An MTX sidecar is a standard, yet minimalistic Node.js CAP project. By default it's added to a subfolder *mtx/sidecar* within your main project, containing just a *package.json* file:

<div class="impl node">

::: code-group

```json [mtx/sidecar/package.json]
```json [Node.js: mtx/sidecar/package.json]
{
"name": "mtx-sidecar", "version": "0.0.0",
"dependencies": {
Expand All @@ -259,16 +236,7 @@ An MTX sidecar is a standard, yet minimalistic Node.js CAP project. By default i
}
```

:::

</div>


<div class="impl java">

::: code-group

```json [mtx/sidecar/package.json]
```json [Java: mtx/sidecar/package.json]
{
"name": "mtx-sidecar", "version": "0.0.0",
"dependencies": {
Expand All @@ -283,16 +251,13 @@ An MTX sidecar is a standard, yet minimalistic Node.js CAP project. By default i
}
}
```

:::

</div>

[Learn more about setting up **MTX sidecars**.](../multitenancy/mtxs#sidecars){.learn-more}

### Add Remote Service Link to Sidecar

<div class="impl node">
#### In Node.js

::: tip
In Node.js apps you usually don't consume services from the sidecar. The *ModelProviderService* is served both, embedded in the main app as well as in the sidecar. The following is documented for the sake of completeness only...
Expand All @@ -311,9 +276,7 @@ You can use the `from-sidecar` preset to tell the CAP runtime to use the remote

[Learn more about configuring ModelProviderService.](../multitenancy/mtxs#model-provider-config){.learn-more}

</div>

<div class="impl java">
#### In CAP Java

You need to configure the CAP Java application to request the CDS model from the Model Provider Service.
This is done in the `application.yaml` file of your application.
Expand All @@ -328,8 +291,6 @@ cds:
extensibility: false
```

</div>

### Test-Drive Sidecar Locally

With the setup as described in place, you can run the main app locally with the Model Provider as sidecar. Simply start the main app and the sidecar in two separate shells:
Expand All @@ -342,27 +303,22 @@ cds watch mtx/sidecar

**Then, start the main app** in the second shell:

<div class="impl node">

```sh
::: code-group
```sh [Node.js]
cds watch
```

</div>

<div class="impl java">

```sh
```sh [Java]
mvn spring-boot:run
```

</div>
:::


#### Remote `getCsn()` Calls to Sidecar at Runtime {.node}
#### Remote `getCsn()` Calls to Sidecar at Runtime in Node.js

When you now run and use our application again as described in the previous section [See Effects in SAP Fiori UIs](#test-fiori-node), you can see in the trace logs that the main app sends `getCsn` requests to the sidecar, which in response to that reads and returns the main app's models. That means, the models from two levels up the folder hierarchy as configured by `root: ../..` for development.
When you now run and use our application again as described in the previous section [See Effects in SAP Fiori UIs](#see-effects-in-sap-fiori-uis), you can see in the trace logs that the main app sends `getCsn` requests to the sidecar, which in response to that reads and returns the main app's models. That means, the models from two levels up the folder hierarchy as configured by `root: ../..` for development.

### See Effects in SAP Fiori UIs {#test-fiori-java .java}
### See Effects in SAP Fiori UIs in CAP Java

To see the effects in the UIs open three anonymous browser windows, one for each user to log in, and:

Expand All @@ -375,7 +331,7 @@ For example the displayed UI should look like that for `erin`:

![A standard SAP Fiori UI including the new columns ratings and isbn that are available to erin.](assets/image-20220630132726831.png)

## Feature Vector Providers {.node}
## Feature Vector Providers in Node.js

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@agoerler Is there anything equivalent in CAP Java?


In principle, features can be toggled *per request* using the `req.features` property (`req` being the standard HTTP req object here, not the CAP runtimes `req` object). This property is expected to contain one of the following:

Expand All @@ -395,7 +351,7 @@ cds.on('bootstrap', app => app.use ((req,res,next) => {

## Feature-Toggled Custom Logic

<div class="impl java">
### In CAP Java

[Evaluate the `FeatureTogglesInfo` in custom code](../../java/reflection-api#using-feature-toggles-in-custom-code) to check if a feature is enabled:

Expand All @@ -409,9 +365,7 @@ if (features.isEnabled("discount")) {
}
```

</div>

<div class="impl node">
### In Node.js

Within your service implementations, you can react on feature toggles by inspecting `cds.context.features` like so:

Expand All @@ -437,6 +391,4 @@ if (reviews) {
// specific coding when feature 'reviews' is enabled...
}
// common coding...
```

</div>
```
2 changes: 1 addition & 1 deletion java/event-queues.md
Original file line number Diff line number Diff line change
Expand Up @@ -524,7 +524,7 @@ A startup log entry shows the configured version:
2024-12-19T11:21:33.253+01:00 INFO 3420 --- [main] cds.services.impl.utils.BuildInfo : application.deployment.version: 1.0.0-SNAPSHOT
```

To bypass the version check for a specific custom outbox, set [`cds.outbox.services.MyCustomOutbox.checkVersion: false`](./developing-applications/properties#cds-outbox-services-<key>-checkVersion).
To bypass the version check for a specific custom outbox, set [`cds.outbox.services.MyCustomOutbox.checkVersion: false`](./developing-applications/properties#cds-outbox-services-<key>-checkversion).


## Troubleshooting
Expand Down
2 changes: 1 addition & 1 deletion node.js/cds-serve.md
Original file line number Diff line number Diff line change
Expand Up @@ -337,7 +337,7 @@ cds.middlewares.before = [
]
```

[Learn more about Feature Vector Providers.](../guides/extensibility/feature-toggles#feature-vector-providers){.learn-more}
[Learn more about Feature Vector Providers.](../guides/extensibility/feature-toggles#feature-vector-providers-in-node-js){.learn-more}


### Current Limitations
Expand Down
Loading