npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@dxfrontier/cds-ts-dispatcher

v2.0.18

Published

The goal of CDS-TS-Dispatcher is to significantly reduce the boilerplate code required to implement TS handlers provided by the SAP CAP framework.

Downloads

581

Readme

SAP ts-node Node.js Express.js json npm

NPM Downloads NPM Downloads NPM Version

GitHub Actions Workflow Status GitHub last commit (branch) GitHub issues GitHub contributors GitHub top language GitHub Repo stars

The goal of CDS-TS-Dispatcher is to significantly reduce the boilerplate code required to implement Typescript handlers provided by the SAP CAP framework.

Table of Contents

Prerequisites

Install @sap/cds-dk globally:

npm install -g @sap/cds-dk typescript ts-node

Installation

Option 1 : Install CDS-TS-Dispatcher - New project

Use the following steps if you want to create a new SAP CAP project.

  1. Create new folder :
mkdir new-sap-cap-project
cd new-sap-cap-project
  1. Initialize the CDS folder structure :
cds init
  1. Add CDS-Typer to your npm package.json:
cds add typer
npm install
  1. Add the the following NPM packages :
npm install @dxfrontier/cds-ts-dispatcher
npm install --save-dev @types/node
  1. Add a tsconfig.json :
tsc --init
  1. It is recommended to use the following tsconfig.json properties:
{
  "compilerOptions": {
    /* Base Options: */
    "esModuleInterop": true,
    "skipLibCheck": true,
    "allowJs": true,
    "strictPropertyInitialization": false,
    "forceConsistentCasingInFileNames": true,
    "allowSyntheticDefaultImports": true,
    "strictNullChecks": true,
    "target": "ES2022",
    "module": "NodeNext",
    "moduleResolution": "NodeNext",

    /* Allow decorators */
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true,

    /* Strictness */
    "strict": true,

    "lib": ["es2022"],

    "outDir": "./gen/srv"
  },
  "include": ["./srv"]
}
  1. Run the CDS-TS server
cds-ts watch

Option 2 : Install CDS-TS-Dispatcher - Existing project

Use the following steps if you want to add only the @dxfrontier/cds-ts-dispatcher to an existing project :

npm install @dxfrontier/cds-ts-dispatcher

It is recommended to use the following tsconfig.json properties:

{
  "compilerOptions": {
    /* Base Options: */
    "esModuleInterop": true,
    "skipLibCheck": true,
    "allowJs": true,
    "strictPropertyInitialization": false,
    "forceConsistentCasingInFileNames": true,
    "allowSyntheticDefaultImports": true,
    "strictNullChecks": true,
    "target": "ES2022",
    "module": "NodeNext",
    "moduleResolution": "NodeNext",

    /* Allow decorators */
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true,

    /* Strictness */
    "strict": true,

    "lib": ["es2022"],

    "outDir": "./gen/srv"
  },
  "include": ["./srv"]
}

[!WARNING] If below message appears

-----------------------------------------------------------------------
WARNING: Package '@sap/cds' was loaded from different installations: [
 '***/node_modules/@sap/cds/lib/index.js',
 '***/node_modules/@dxfrontier/cds-ts-dispatcher/node_modules/@sap/cds/lib/index.js'
] Rather ensure a single install only to avoid hard-to-resolve errors.
-----------------------------------------------------------------------

Run the following command :

npm install @sap/cds@latest

Option 3 : Install CDS-TS-Dispatcher - .devcontainer on VSCode & Docker

The CDS-TS-Dispatcher dev container repository contains the CDS-TS-Dispatcher & CDS-TS-Repository and all dependencies needed to boot a new project :

Tools installed inside of the container :

  • Controller - Service - Repository project structure folders :
    • controller
    • service
    • repository
    • middleware
    • util
    • test
  • ESLint, Prettier
  • VSCode Extensions best extensions for SAP CAP TypeScript development
  • Cloud MTA Build tool for building MTA file
  • Cloud Foundry CLI (CF)
  • Git, Cds, Npm, Node
  • CDS-Typer for building typescript entities out of CDS files
  • tsconfig.json, .eslintrc, .prettierrc - predefined properties
  • package.json - predefined scripts

Steps

  1. Install Docker desktop
  2. Clone CDS-TS-Dispatcher devcontainer using below command :
git clone https://github.com/dxfrontier/cds-ts-dispatcher-dev-container
  1. Open project in VSCode using:
code cds-ts-dispatcher-dev-container
  1. Change GIT remote origin to your origin
git remote remove origin
git remote add origin https://github.com/user/YOUR_GIT_REPOSITORY.git
git branch -M main
git push -u origin main
  1. Install Remote development pack VScode extension

  2. COMMAND + SHIFT + P on MacOS or CTRL + SHIFT + P on Windows

    1. Type - Rebuild and Reopen in Container - This step will start creating the container project and start the Node server.
  3. Start development as usual.

Generate CDS Typed entities

Option 1 - Recommended

Execute the following commands :

cds add typer
npm install

[!TIP] If above option is being used, this means whenever we change a .CDS file the changes will reflect in the generated @cds-models folder.

Option 2

Execute the command :

npx @cap-js/cds-typer "*" --outputDirectory ./srv/util/types/entities
  • Target folder :./srv/util/types/entities - Change to your desired destination folder.

Important

[!CAUTION] Import always the generated entities from the service folders and not from the index.ts

alt text

[!TIP] By default cds-typer will create in your package.json a quick path alias like :

"imports": {
  "#cds-models/*": "./@cds-models/*/index.js"
}

Use import helper to import entities from #cds-models like example :

  • import { Book } from '#cds-models/CatalogService';

Usage

Architecture

We recommend adhering to the Controller-Service-Repository design pattern using the following folder structure:

  1. EntityHandler (Controller) - Responsible for managing the REST interface to the business logic implemented in ServiceLogic
  2. ServiceLogic (Service) - Contains business logic implementations
  3. Repository (Repository) - This component is dedicated to handling entity manipulation operations by leveraging the power of CDS-QL.

Controller-Service-Repository suggested folder structure

alt text <= expanded folders => alt text

CDSDispatcher

CDSDispatcher(entities : Constructable[])

The CDSDispatcher constructor allows you to create an instance for dispatching and managing entities.

Parameters

  • entities (Array): An array of Entity handler(s) (Constructable) that represent the entities in the CDS.

Method

Example

import { CDSDispatcher } from '@dxfrontier/cds-ts-dispatcher';

export = new CDSDispatcher([
  // Entities
  BookHandler,
  ReviewHandler,
  BookStatsHandler,
  // Draft
  BookEventsHandler,
  // Unbound actions
  UnboundActionsHandler,
]).initialize();

// or use
// module.exports = new CDSDispatcher([ ...

Visual image

Decorators

Class

@EntityHandler

@EntityHandler(entity: CDSTyperEntity)

The @EntityHandler decorator is utilized at the class-level to annotate a class with the specific entity that will be used in all handlers.

When @EntityHandler decorator applied to a class all events Before, After, On will be triggered based on the argument entity.

Parameters

  • entity (CDSTyperEntity): A specialized class generated using the CDS-Typer.

Example

import { EntityHandler } from '@dxfrontier/cds-ts-dispatcher';
import { MyEntity } from 'YOUR_CDS_TYPER_ENTITIES_LOCATION';

@EntityHandler(MyEntity)
export class BookHandler {
  // ...
  constructor() {}
  // ... all events like @AfterRead, @BeforeRead ...
}

[!TIP] After creation of BookHandler class, you can import it into the CDSDispatcher.

import { CDSDispatcher } from '@dxfrontier/cds-ts-dispatcher';

export = new CDSDispatcher([
  // Entities
  BookHandler,
  // Unbound actions
  // ...
]).initialize();

[!NOTE] MyEntity was generated using CDS-Typer and imported in the class.

@ServiceLogic

@ServiceLogic()

The @ServiceLogic decorator is utilized at the class-level to annotate a class as a specialized class containing only business logic.

Example

import { ServiceLogic } from '@dxfrontier/cds-ts-dispatcher';

@ServiceLogic()
export class CustomerService {
  // ...
  constructor() {}
  // ...
}

[!TIP] When applying @ServiceLogic() decorator, the class becomes eligible to be used with Inject decorator for Dependency injection.

@Repository

@Repository()

The @Repository decorator is utilized as a class-level annotation that designates a particular class as a specialized Repository, this class should contain only CDS-QL code.

import { Repository } from '@dxfrontier/cds-ts-dispatcher';

@Repository()
export class CustomerRepository {
  // ...
  constructor() {}
  // ...
}

[!TIP] When applying @Repository() decorator, the class becomes eligible to be used with Inject decorator for Dependency injection.

[Optional] - CDS-TS-Repository - BaseRepository

The CDS-TS-Repository - BaseRepository was designed to reduce the boilerplate code required to implement data access layer for persistance entities.

It simplifies the implementation by offering a set of ready-to-use actions for interacting with the database. These actions include:

  • .create(): Create new records in the database.
  • .findAll(): Retrieve all records from the database.
  • .find(): Query the database to find specific data.
  • .delete(): Remove records from the database.
  • .exists(): Check the existence of data in the database.
  • and many more ...

Example

import { Repository } from '@dxfrontier/cds-ts-dispatcher';
import { BaseRepository } from '@dxfrontier/cds-ts-repository';

import { MyEntity } from 'YOUR_CDS_TYPER_ENTITIES_LOCATION';

@Repository()
export class CustomerRepository extends BaseRepository<MyEntity> {
  constructor() {
    super(MyEntity);
  }

  public async aMethod() {
    const created = await this.create(...)
    const createdMany = await this.createMany(...)
    const updated = await this.update(...)
    // ...
  }
}

To get started, refer to the official documentation CDS-TS-Repository - BaseRepository. Explore the capabilities it offers and enhance your data access layer with ease.

[!NOTE] MyEntity was generated using CDS-Typer and imported in the class.

@UnboundActions

@UnboundActions()

The @UnboundActions decorator is utilized at the class-level to annotate a class as a specialized class which will be used only for Unbound actions.

The following decorators can be used inside of @UnboundActions() :

Example

import { UnboundActions, OnAction, OnFunction, OnEvent, Req, Next, Error } from '@dxfrontier/cds-ts-dispatcher';
import { MyAction, MyFunction, MyEvent } from 'YOUR_CDS_TYPER_ENTITIES_LOCATION';

import type { ActionRequest, ActionReturn, TypedRequest, Request, NextEvent } from '@dxfrontier/cds-ts-dispatcher';

@UnboundActions()
export class UnboundActionsHandler {
  // ... @Inject dependencies, if needed.

  constructor() {}

  // Unbound action
  @OnAction(MyAction)
  private async onActionMethod(
    @Req() req: ActionRequest<typeof MyAction>,
    @Next() next: NextEvent,
  ): ActionReturn<typeof MyAction> {
    // ...
  }

  // Unbound Function
  @OnFunction(MyFunction)
  private async onFunctionMethod(
    @Req() req: ActionRequest<typeof MyFunction>,
    @Next() next: NextEvent,
  ): ActionReturn<typeof MyFunction> {
    // ...
  }

  // Unbound event
  @OnEvent(MyEvent)
  private async onEventMethod(@Req() req: TypedRequest<MyEvent>) {
    // ...
  }

  // Unbound error
  @OnError()
  private onErrorMethod(@Error() err: Error, @Req() req: Request) {
    // ...
  }
}

Imported it in the CDSDispatcher

import { CDSDispatcher } from '@dxfrontier/cds-ts-dispatcher';

export = new CDSDispatcher([ UnboundActionsHandler, ...])
// or
// use module.exports = new CDSDispatcher( ... )

[!NOTE] The reason behind introducing a distinct decorator for Unbound actions stems from the fact that these actions are not associated with any specific Entity but instead these actions belongs to the Service itself.

@Use

@Use(...Middleware[])

The @Use decorator simplifies the integration of middlewares into your classes.

When @Use decorator applied at the class-level this decorator inject middlewares into the class and gain access to the req: Request and next: NextMiddleware middleware across all events (@AfterRead, @OnRead ...) within that class.

Middleware decorators can perform the following tasks:

  • Execute any code.
  • Make changes to the request object.
  • End the request-response cycle.
  • Call the next middleware function in the stack.
  • If the current middleware function does not end the request-response cycle, it must call next() to pass control to the next middleware function. Otherwise, the request will be left hanging.

Parameters

  • ...Middleware[]): Middleware classes to be injected.

Example: middleware implementation

import type { MiddlewareImpl, NextMiddleware, Request } from '@dxfrontier/cds-ts-dispatcher';

export class MiddlewareClass implements MiddlewareImpl {
  public async use(req: Request, next: NextMiddleware) {
    console.log('Middleware use method called.');

    await next(); // call next middleware
  }
}

Example usage

import { EntityHandler, Use, Inject, SRV } from '@dxfrontier/cds-ts-dispatcher';

import { MyEntity } from 'YOUR_CDS_TYPER_ENTITIES_LOCATION';
import { Middleware1, Middleware2, MiddlewareN } from 'YOUR_MIDDLEWARE_LOCATION';

import type { Service } from '@dxfrontier/cds-ts-dispatcher';

@EntityHandler(MyEntity)
@Use(Middleware1, Middleware2, MiddlewareN)
export class CustomerHandler {
  // ...
  @Inject(SRV) private srv: Service;
  // ...
  constructor() {}
  // ...
}

[!TIP]

  1. Think of it (middleware) like as a reusable class, enhancing the functionality of all events within the class.
  2. Middlewares when applied with @Use are executed before the normal events.
  3. If you need to apply middleware to a method you should use the method specific @Use decorator .

[!WARNING] If req.reject() is used inside of middleware this will stop the stack of middlewares, this means that next middleware will not be executed.

[!NOTE] MyEntity was generated using CDS-Typer and imported in the class.

Field

@Inject

@Inject(serviceIdentifier: ServiceIdentifierOrFunc<unknown>)

The @Inject decorator is utilized as a field-level decorator and allows you to inject dependencies into your classes.

Parameters

  • serviceIdentifier(ServiceIdentifierOrFunc<unknown>): A Class representing the service to inject.

Example

import { EntityHandler, Inject, SRV } from "@dxfrontier/cds-ts-dispatcher";
import type { Service } from '@dxfrontier/cds-ts-dispatcher';

import { MyEntity } from 'YOUR_CDS_TYPER_ENTITIES_LOCATION';

@EntityHandler(MyEntity)
export class CustomerHandler {
  ...
  @Inject(CustomerService) private customerService: CustomerService
  @Inject(CustomerRepository) private customerService: CustomerRepository
  @Inject(AnyOtherInjectableClass) private repository: AnyOtherInjectableClass

  @Inject(SRV) private srv: Service
  // ...
  constructor() {}
  // ...
}

[!NOTE] MyEntity was generated using CDS-Typer and imported in the class.

@Inject(SRV)

@Inject(SRV) private srv: Service

This specialized @Inject can be used as a constant in :

It can be accessed trough this.srv and contains the CDS.ApplicationService for further enhancements.

Example

import { EntityHandler, Inject, SRV } from '@dxfrontier/cds-ts-dispatcher';

import { MyEntity } from 'YOUR_CDS_TYPER_ENTITIES_LOCATION';

import type { Service } from '@dxfrontier/cds-ts-dispatcher';

@EntityHandler(MyEntity)
// OR @ServiceLogic()
// OR @Repository()
// OR @UnboundActions()
export class CustomerHandler {
  // @Inject dependencies
  @Inject(SRV) private srv: Service;

  constructor() {}
  // ...
}

[!NOTE] MyEntity was generated using CDS-Typer and imported in the the class.

Parameter

@Req

@Req()

The @Req decorator is utilized at the parameter level to annotate a parameter with the Request object, providing access to request-related information of the current event.

Return

  • Request: An instance of @sap/cds - Request

Example

import { EntityHandler, Req, Results } from '@dxfrontier/cds-ts-dispatcher';
import { MyEntity } from 'YOUR_CDS_TYPER_ENTITIES_LOCATION';

import type { Request } from '@dxfrontier/cds-ts-dispatcher';

@EntityHandler(MyEntity)
export class BookHandler {
  // ...
  constructor() {}
  // ... all events like @AfterRead, @BeforeRead ...

  @AfterRead()
  private async aMethod(@Req() req: Request, @Results() results: MyEntity[]) {
    // ... req...
  }
}
@Res

@Res()

The @Res decorator is utilized at the parameter level to annotate a parameter with the Request.http.res - (Response) object, providing access to response-related information of the current event and it can be used to enhance the Response.

Return

  • RequestResponse: An instance of RequestResponse providing you response-related information.

Example

import { EntityHandler, Req, Results } from '@dxfrontier/cds-ts-dispatcher';
import { MyEntity } from 'YOUR_CDS_TYPER_ENTITIES_LOCATION';

import type { Request, RequestResponse } from '@dxfrontier/cds-ts-dispatcher';

@EntityHandler(MyEntity)
export class BookHandler {
  // ...
  constructor() {}
  // ... all events like @AfterRead, @BeforeRead ...

  @AfterRead()
  private async aMethod(@Req() req: Request, @Res() response: RequestResponse, @Results() results: MyEntity[]) {
    // Example: we assume we want to add a new header language on the response
    // We use => res.setHeader('Accept-Language', 'DE_de');
  }
}

[!TIP] Decorator @Res can be used in all After, Before and On events.

@Results / @Result

@Results() / @Result

The @Results decorator is utilized at the parameter level to annotate a parameter with the request Results.

Return

  • Array / object: Contains the OData Request Body.

Example

import { EntityHandler, Req, Results } from '@dxfrontier/cds-ts-dispatcher';
import { MyEntity } from 'YOUR_CDS_TYPER_ENTITIES_LOCATION';

import type { Request } from '@dxfrontier/cds-ts-dispatcher';

@EntityHandler(MyEntity)
export class BookHandler {
  // ...
  constructor() {}
  // ... all events like @AfterRead, @BeforeRead ...

  @AfterRead()
  private async aMethod(@Req() req: Request, @Results() results: MyEntity[]) {
    // ...
  }
}

[!TIP] When using @AfterCreate(), @AfterUpdate() and @AfterDelete() it's recommended to use the @Result decorator for single object result and @Results for arrays of objects.

@AfterCreate()
@AfterUpdate()
private async aMethod(
   @Result() result: Book, // <== @Result() decorator used to annotate it's a an object and not an array
   @Req() req: Request,
 ) {
   // ...
 }

@AfterRead()
private async aMethod(
  @Results() result: Book[], // <== @Results() decorator used to annotate as array of objects
  @Req() req: Request,
) {
  // ...
}

@AfterDelete()
private async aMethod(
@Result() deleted: boolean, // <== @Result() decorator used to annotate as a boolean
@Req() req: Request,
) {
  // ...
}

[!TIP] Decorators @Results() and @Result() can be applied to all After events.

@Next

@Next()

The @Next decorator is utilized at the parameter level to annotate a parameter with the Next function, which is used to proceed to the next event in the chain of execution.

Return

  • NextEvent: The next event in chain to be called.

Example

import { EntityHandler, Req, Results } from '@dxfrontier/cds-ts-dispatcher';
import { MyEntity } from 'YOUR_CDS_TYPER_ENTITIES_LOCATION';

import type { Request, NextEvent } from '@dxfrontier/cds-ts-dispatcher';

@EntityHandler(MyEntity)
export class BookHandler {
  // ...
  constructor() {}
  // ... all events like @AfterRead, @BeforeRead, @OnCreate ...

  @OnCreate()
  public async onCreate(@Req() req: TypedRequest<MyEntity>, @Next() next: NextEvent) {
    return next();
  }
}

[!TIP] Decorator @Next can be applied to all On, On - draft event decorators.

@Error

@Error()

The @Error decorator is utilized at the parameter level to annotate a parameter with the Error and contains information regarding the failed Request.

Return

  • Error: An instance of type Error.

Example

import { UnboundActions, Req, Error } from '@dxfrontier/cds-ts-dispatcher';
import { MyEntity } from 'YOUR_CDS_TYPER_ENTITIES_LOCATION';

import type { Request } from '@dxfrontier/cds-ts-dispatcher';

@UnboundActions()
export class UnboundActionsHandler {
  // ...
  constructor() {}

  @OnError()
  public onError(@Error() err: Error, @Req() req: Request): void {
    // ...
  }
}

[!TIP] Decorator @Error can be applied to @OnError() decorator which resides inside of the @UnboundActions().

@Jwt

@Jwt()

The @Jwt decorator is utilized at the parameter level. It will retrieve the to retrieve JWT from the Request that is based on the node req.http.req - IncomingMessage.

Fails if no authorization header is given or has the wrong format.

Return

  • string | undefined : The retrieved JWT token or undefined if no token was found.

Example

import { EntityHandler, Req, Results, Jwt } from '@dxfrontier/cds-ts-dispatcher';
import { MyEntity } from 'YOUR_CDS_TYPER_ENTITIES_LOCATION';

import type { Request } from '@dxfrontier/cds-ts-dispatcher';

@EntityHandler(MyEntity)
export class BookHandler {
  // ...
  constructor() {}
  // ... all events like @AfterRead, @BeforeRead ...

  @AfterRead()
  private async aMethod(@Req() req: Request, @Results() results: MyEntity[], @Jwt(): string | undefined) {
    // ... req...
  }
}

[!IMPORTANT] Expected format is Bearer <TOKEN>.

@IsPresent

@IsPresent<Key extends CRUDQueryKeys>(key: Key, property: PickQueryPropsByKey<Key>)

The @IsPresent decorator is utilized at the parameter level. It allows you to verify the existence of a specified Query property values.

Parameters

  • key (string): Specifies the type of query operation. Accepted values are INSERT, SELECT, UPDATE, UPSERT, DELETE.
  • property (string): Specifies the property based on the key.

Return

  • boolean: This decorator returns true if property value is filled, false otherwise

Example

import { EntityHandler, Req, Results, IsPresent } from '@dxfrontier/cds-ts-dispatcher';
import { MyEntity } from 'YOUR_CDS_TYPER_ENTITIES_LOCATION';

import type { Request } from '@dxfrontier/cds-ts-dispatcher';

@EntityHandler(MyEntity)
class BookHandler {
  // ...
  constructor() {}

  @AfterRead()
  private async aMethod(
    @Req() req: Request,
    @Results() results: MyEntity[],

    @IsPresent('SELECT', 'columns') columnsPresent: boolean,
  ) {
    if (columnsPresent) {
      // ...
    }

    // ...
  }
}

[!TIP] Decorator @IsPresent() works well with @GetQuery().

@IsRole

@IsRole(...roles: string[])

The @IsRole decorator is utilized at the parameter level. It allows you to verify if the User has assigned a given role.

It applies an OR logic on the specified roles, meaning it checks if at least one of the specified roles is assigned.

Parameters

  • role (...string[]): An array of role names to check if are assigned.

Return

  • boolean: This decorator returns true if at least one of the specified roles is assigned to the current request user, otherwise false.

Example

import { EntityHandler, Req, Results, IsPresent, IsRole } from '@dxfrontier/cds-ts-dispatcher';
import { MyEntity } from 'YOUR_CDS_TYPER_ENTITIES_LOCATION';

import type { Request } from '@dxfrontier/cds-ts-dispatcher';

@EntityHandler(MyEntity)
class BookHandler {
  // ...
  constructor() {}

  @AfterRead()
  private async aMethod(
    @Req() req: Request,
    @Results() results: MyEntity[],

    @IsRole('role', 'anotherRole') roleAssigned: boolean,
  ) {
    if (roleAssigned) {
      // ...
    }

    // ...
  }
}

[!TIP] The role names correspond to the values of @requires and the @restrict.grants.to annotations in your CDS models.

@IsColumnSupplied

@IsColumnSupplied<T>(field : keyof T)

The @IsColumnSupplied<T>() decorator is utilized at the parameter level. It allows your to verify the existence of a column in the SELECT, INSERT or UPSERT Query.

Parameters

  • column (string): A string representing the name of the column to be verified.

Return :

  • boolean: This decorator returns true if column was found, false otherwise

Example

import { EntityHandler, Req, Results, IsPresent } from '@dxfrontier/cds-ts-dispatcher';
import { MyEntity } from 'YOUR_CDS_TYPER_ENTITIES_LOCATION';

import type { Request } from '@dxfrontier/cds-ts-dispatcher';

@EntityHandler(MyEntity)
class BookHandler {
  // ...
  constructor() {}

  @AfterRead()
  private async aMethod(
    @Req() req: Request,
    @Results() results: MyEntity[],

    @IsColumnSupplied<MyEntity>('price') priceSupplied: boolean,
  ) {
    if (priceSupplied) {
      // ...
    }

    // ...
  }
}
@GetQuery

@GetQuery<Key extends CRUDQueryKeys>(key: Key, property: PickQueryPropsByKey<Key>)

The @GetQuery decorator is utilized at the parameter level. It allows you to retrieve Query property values.

Parameters

  • key (string): Specifies the type of query operation. Accepted values are INSERT, SELECT, UPDATE, UPSERT, DELETE.
  • property (string): Specifies the property based on the key.

Return: Varies based on the specified property :

    • @GetQuery('SELECT', 'columns') columns: GetQueryType['columns']['forSelect']
    • @GetQuery('SELECT', 'distinct') distinct: GetQueryType['distinct']
    • @GetQuery('SELECT', 'excluding') excluding: GetQueryType['excluding']
    • @GetQuery('SELECT', 'from') from: GetQueryType['from']['forSelect']
    • @GetQuery('SELECT', 'groupBy') groupBy: GetQueryType['groupBy']
    • @GetQuery('SELECT', 'having') having: GetQueryType['having']
    • @GetQuery('SELECT', 'limit') limit: GetQueryType['limit']
    • @GetQuery('SELECT', 'limit.rows') limitRows: GetQueryType['limit']['rows']
    • @GetQuery('SELECT', 'limit.offset') limitOffset: GetQueryType['limit']['offset']
    • @GetQuery('SELECT', 'mixin') mixin: GetQueryType['mixin']
    • @GetQuery('SELECT', 'one') one: GetQueryType['one']
    • @GetQuery('SELECT', 'orderBy') orderBy: GetQueryType['orderBy']
    • @GetQuery('SELECT', 'where') where: GetQueryType['where']
    • @GetQuery('INSERT', 'as') as: GetQueryType['as']
    • @GetQuery('INSERT', 'columns') columns: GetQueryType['columns']['forInsert']
    • @GetQuery('INSERT', 'entries') entries: GetQueryType['entries']
    • @GetQuery('INSERT', 'into') into: GetQueryType['into']
    • @GetQuery('INSERT', 'rows') rows: GetQueryType['rows']
    • @GetQuery('INSERT', 'values') values: GetQueryType['values']
    • @GetQuery('UPDATE', 'data') data: GetQueryType['data']
    • @GetQuery('UPDATE', 'entity') entity: GetQueryType['entity']
    • @GetQuery('UPDATE', 'where') where: GetQueryType['where']
    • @GetQuery('UPSERT', 'columns') columns: GetQueryType['columns'][forUpsert]
    • @GetQuery('UPSERT', 'entries') entries: GetQueryType['entries']
    • @GetQuery('UPSERT', 'into') into: GetQueryType['into']
    • @GetQuery('UPSERT', 'rows') rows: GetQueryType['rows']
    • @GetQuery('UPSERT', 'values') values: GetQueryType['values']
    • @GetQuery('DELETE', 'from') from: GetQueryType['from'][forDelete]

    • @GetQuery('DELETE', 'where') columns: GetQueryType['where']

Example

import { EntityHandler, Req, Results, IsPresent, GetQuery } from '@dxfrontier/cds-ts-dispatcher';
import { MyEntity } from 'YOUR_CDS_TYPER_ENTITIES_LOCATION';

import type { Request, GetQueryType } from '@dxfrontier/cds-ts-dispatcher';

@EntityHandler(MyEntity)
class BookHandler {
  // ...
  constructor() {}

  @AfterRead()
  private async aMethod(
    @Req() req: Request,
    @Results() results: MyEntity[],

    // Check existence of columns
    @IsPresent('SELECT', 'columns') columnsPresent: boolean,

    // Get columns
    @GetQuery('SELECT', 'columns') columns: GetQueryType['columns']['forSelect'],

    @GetQuery('SELECT', 'orderBy') orderBy: GetQueryType['orderBy'],
    @GetQuery('SELECT', 'groupBy') groupBy: GetQueryType['groupBy'],
  ) {
    if (columnsPresent) {
      // do something with columns values
      // columns.forEach(...)
    }

    // ...
  }
}

[!TIP] Decorator @GetQuery() can be used to get the Query property and @IsPresent() can check if the Query property is empty or not.

@GetRequest

@GetRequest(property : keyof Request)

The @GetRequest decorator is utilized at the parameter level. It allows you tu retrieve the specified property value from the Request object.

Parameters

  • property (string): Specifies the property to retrieve from the Request object.

Return: Varies based on the specified property :

  • @GetRequest('entity') entity: Request['entity'],
  • @GetRequest('event') event: Request['event'],
  • @GetRequest('features') features: Request['features'],
  • @GetRequest('headers') headers: Request['headers'],
  • @GetRequest('http') http: Request['http'],
  • @GetRequest('id') id: Request['id'],
  • @GetRequest('locale') locale: Request['locale'],
  • @GetRequest('method') method: Request['method'],
  • @GetRequest('params') params: Request['params'],
  • @GetRequest('query') query: Request['query'],
  • @GetRequest('subject') subject: Request['subject'],
  • @GetRequest('target') target: Request['target'],
  • @GetRequest('tenant') tenant: Request['tenant'],
  • @GetRequest('timestamp') timestamp: Request['timestamp'],
  • @GetRequest('user') user: Request['user'],

Example

import { EntityHandler, Results, GetRequest } from '@dxfrontier/cds-ts-dispatcher';
import { MyEntity } from 'YOUR_CDS_TYPER_ENTITIES_LOCATION';

import type { GetTypeLocale, GetTypeMethod, Request } from '@dxfrontier/cds-ts-dispatcher';

@EntityHandler(MyEntity)
class BookHandler {
  // ...
  constructor() {}

  @AfterRead()
  private async aMethod(
    // @Req() req: Request, we assume we don't need the hole Request object and we need only 'locale' and 'method'
    @Results() results: MyEntity[],

    @GetRequest('locale') locale: Request['locale'],
    @GetRequest('method') method: Request['method'],
  ) {
    // do something with 'locale' and 'method' ...
  }
}

[!TIP] Type Request can be import from :

import type { Request } from '@dxfrontier/cds-ts-dispatcher';
@SingleInstanceSwitch

@SingleInstanceSwitch

The @SingleInstanceSwitch() decorator is applied at the parameter level.

It allows you to manage different behaviors based on whether the request is for a single entity instance or an entity set, the parameter assigned to the decorator will behave like a switch.

Return

  • true when the Request is single instance
  • false when the Request is entity set

Example 1

Single request : http://localhost:4004/odata/v4/main/MyEntity(ID=2f12d711-b09e-4b57-b035-2cbd0a023a09)

import { AfterRead, SingleInstanceCapable } from "@dxfrontier/cds-ts-dispatcher";
import type { TypedRequest } from '@dxfrontier/cds-ts-dispatcher';

import { MyEntity } from 'YOUR_CDS_TYPER_ENTITIES_LOCATION';

@AfterRead()
private async singeInstanceMethodAndEntitySet(@Results() results : MyEntity[], @Req() req: TypedRequest<MyEntity>, @SingleInstanceSwitch() isSingleInstance: boolean) {
  if(isSingleInstance) {
    // This will be executed only when single instance is called : http://localhost:4004/odata/v4/main/MyEntity(ID=2f12d711-b09e-4b57-b035-2cbd0a023a09)
    return this.customerService.handleSingleInstance(req)
  }

  // nothing to entity set
}

Example 2

Entity request : http://localhost:4004/odata/v4/main/MyEntity

import { AfterRead, SingleInstanceCapable } from "@dxfrontier/cds-ts-dispatcher";
import type { TypedRequest } from '@dxfrontier/cds-ts-dispatcher';

import { MyEntity } from 'YOUR_CDS_TYPER_ENTITIES_LOCATION';

@AfterRead()
private async singeInstanceMethodAndEntitySet(@Results() results : MyEntity[], @Req() req: TypedRequest<MyEntity>, @SingleInstanceSwitch() isSingleInstance: boolean) {
  if(isSingleInstance) {
    // This will be executed only when single instance is called : http://localhost:4004/odata/v4/main/MyEntity(ID=2f12d711-b09e-4b57-b035-2cbd0a023a09)
    // ...
  }

  // ... this will be executed when entity set is called : http://localhost:4004/odata/v4/main/MyEntity
  results[0] = {
    name : 'new value'
  }
}

[!TIP] Decorator @SingleInstanceSwitch can be used together with the following decorator events:

[!NOTE] MyEntity was generated using CDS-Typer and imported in the the class.

Method-active entity

Before

Use @BeforeCreate(), @BeforeRead(), @BeforeUpdate(), @BeforeDelete() to register handlers to run before .on handlers, frequently used for validating user input.

The handlers receive one argument:

  • req of type TypedRequest

See also the official SAP JS CDS-Before event

[!TIP] If @odata.draft.enabled: true to manage event handlers for draft version you can use

  • @BeforeCreateDraft()
  • @BeforeReadDraft()
  • @BeforeUpdateDraft()
  • @BeforeDeleteDraft()
@BeforeCreate

@BeforeCreate()

Example

import { BeforeCreate } from "@dxfrontier/cds-ts-dispatcher";
import type { TypedRequest } from '@dxfrontier/cds-ts-dispatcher';

import { MyEntity } from 'YOUR_CDS_TYPER_ENTITIES_LOCATION';

@BeforeCreate()
private async beforeCreateMethod(@Req() req: TypedRequest<MyEntity>) {
  // ...
}

Equivalent to 'JS'

this.before('CREATE', MyEntity, async (req) => {
  // ...
});

[!IMPORTANT] It is important to note that the decorator @BeforeCreate() will be triggered based on the EntityHandler argument => MyEntity.

[!NOTE] MyEntity was generated using CDS-Typer and imported in the the class.

@BeforeRead

@BeforeRead()

Example

import { BeforeRead } from "@dxfrontier/cds-ts-dispatcher";
import type { TypedRequest } from '@dxfrontier/cds-ts-dispatcher';

import { MyEntity } from 'YOUR_CDS_TYPER_ENTITIES_LOCATION';

@BeforeRead()
private async beforeReadMethod(@Req() req: TypedRequest<MyEntity>) {
  // ...
}

Equivalent to 'JS'

this.before('READ', MyEntity, async (req) => {
  // ...
});

[!IMPORTANT] Decorator @BeforeRead() will be triggered based on the EntityHandler argument => MyEntity.

[!NOTE] MyEntity was generated using CDS-Typer and imported in the the class.

@BeforeUpdate

@BeforeUpdate()

Example

import { BeforeUpdate } from "@dxfrontier/cds-ts-dispatcher";
import type { TypedRequest } from '@dxfrontier/cds-ts-dispatcher';

import { MyEntity } from 'YOUR_CDS_TYPER_ENTITIES_LOCATION';

@BeforeUpdate()
private async beforeUpdateMethod(@Req() req: TypedRequest<MyEntity>) {
  // ...
}

Equivalent to 'JS'

this.before('UPDATE', MyEntity, async (req) => {
  // ...
});

[!IMPORTANT] Decorator @BeforeUpdate() will be triggered based on the EntityHandler argument => MyEntity

[!NOTE] MyEntity was generated using CDS-Typer and imported in the the class.

@BeforeDelete

@BeforeDelete()

Example

import { BeforeDelete } from "@dxfrontier/cds-ts-dispatcher";
import type { TypedRequest } from '@dxfrontier/cds-ts-dispatcher';

import { MyEntity } from 'YOUR_CDS_TYPER_ENTITIES_LOCATION';

@BeforeDelete()
private async beforeDeleteMethod(@Req() req: TypedRequest<MyEntity>) {
  // ...
}

Equivalent to 'JS'

this.before('DELETE', MyEntity, async (req) => {
  // ...
});

[!IMPORTANT] Decorator @BeforeDelete() will be triggered based on the EntityHandler argument => MyEntity.

[!NOTE] MyEntity was generated using CDS-Typer and imported in the the class.

After

Use @AfterCreate(), @AfterRead(), @AfterUpdate(), @AfterDelete() register handlers to run after the .on handlers, frequently used to enrich outbound data.

The handlers receive two arguments:

| Parameters | Decorator | Description | | -------------- | --------------------------------- | -------------------------------------------------------------------------- | | results, req | @AfterRead | An array of type MyEntity[] and the Request. | | result, req | @AfterUpdate @AfterCreate | An object of type MyEntity and the Request. | | deleted, req | @AfterDelete | A boolean indicating whether the instance was deleted and the Request. |

[!TIP] If @odata.draft.enabled: true to manage event handlers for draft version you can use :

  • @AfterCreateDraft()
  • @AfterReadDraft()
  • @AfterReadDraftSingleInstance()
  • @AfterUpdateDraft()
  • @AfterDeleteDraft()
@AfterCreate

@AfterCreate()

Example

import { AfterCreate } from "@dxfrontier/cds-ts-dispatcher";
import type { TypedRequest } from '@dxfrontier/cds-ts-dispatcher';

import { MyEntity } from 'YOUR_CDS_TYPER_ENTITIES_LOCATION';

@AfterCreate()
private async afterCreateMethod(@Result() @Result() result: MyEntity, @Req() req: TypedRequest<MyEntity>) {
  // ...
}

Equivalent to 'JS'

this.after('CREATE', MyEntity, async (result, req) => {
  // ...
});

[!IMPORTANT] Decorator @AfterCreate() will be triggered based on the EntityHandler argument => MyEntity.

[!NOTE] MyEntity was generated using CDS-Typer and imported in the the class.

@AfterRead

@AfterRead()

Example

import { AfterRead, Results, Req } from "@dxfrontier/cds-ts-dispatcher";
import type { TypedRequest } from '@dxfrontier/cds-ts-dispatcher';

import { MyEntity } from 'YOUR_CDS_TYPER_ENTITIES_LOCATION';

@AfterRead()
private async afterReadMethod(@Results() results: MyEntity[], @Req() req: TypedRequest<MyEntity>) {
  // ...
}

Equivalent to 'JS'

this.after('READ', MyEntity, async (results, req) => {
  // ...
});

[!IMPORTANT] Decorator @AfterRead() will be triggered based on the EntityHandler argument MyEntity.

[!NOTE] MyEntity was generated using CDS-Typer and imported in the the class.

@AfterUpdate

@AfterUpdate()

Example

Single request : http://localhost:4004/odata/v4/main/MyEntity(ID=2f12d711-b09e-4b57-b035-2cbd0a023a09)

import { AfterUpdate } from "@dxfrontier/cds-ts-dispatcher";
import type { TypedRequest } from '@dxfrontier/cds-ts-dispatcher';

import { MyEntity } from 'YOUR_CDS_TYPER_ENTITIES_LOCATION';

@AfterUpdate()
private async afterUpdateMethod(@Result() result: MyEntity, @Req() req: TypedRequest<MyEntity>) {
  // ...
}

Equivalent to 'JS'

this.after('UPDATE', MyEntity, async (result, req) => {
  // ...
});

[!IMPORTANT] Decorator @AfterUpdate() will be triggered based on the EntityHandler argument => MyEntity.

[!NOTE] MyEntity was generated using CDS-Typer and imported in the the class.

@AfterDelete

@AfterDelete()

Example

import { AfterDelete} from "@dxfrontier/cds-ts-dispatcher";
import type { Request } from '@dxfrontier/cds-ts-dispatcher';

import { MyEntity } from 'YOUR_CDS_TYPER_ENTITIES_LOCATION';

@AfterDelete()
private async afterDeleteMethod(@Result() deleted: boolean, @Req() req: Request) {
  // ...
}

Equivalent to 'JS'

this.after('DELETE', MyEntity, async (deleted, req) => {
  // ...
});

[!IMPORTANT] Decorator @AfterDelete() will be triggered based on the EntityHandler argument => MyEntity.

[!NOTE] MyEntity was generated using CDS-Typer and imported in the the class.

On

Use @OnCreate(), @OnRead(), @OnUpdate(), @OnDelete(), OnAction(), @OnFunction(), @OnBoundAction(), @OnBoundFunction() handlers to fulfill requests, e.g. by reading/writing data from/to databases handlers.

The handlers receive two arguments:

  • req of type TypedRequest
  • next of type NextEvent

[!TIP] If @odata.draft.enabled: true to manage event handlers for draft version you can use :

  • @OnCreateDraft()
  • @OnReadDraft()
  • @OnUpdateDraft()
  • @OnDeleteDraft()
  • @OnBoundActionDraft()
  • @OnBoundFunctionDraft()
@OnCreate

@OnCreate()

Example

import { OnCreate, Next } from "@dxfrontier/cds-ts-dispatcher";
import type { TypedRequest, NextEvent } from '@dxfrontier/cds-ts-dispatcher';

import { MyEntity } from 'YOUR_CDS_TYPER_ENTITIES_LOCATION';

@OnCreate()
private async onCreateMethod(@Req() req: TypedRequest<MyEntity>, @Next() next: NextEvent) {
  // ...

  return next();
}

Equivalent to 'JS'

this.on('CREATE', MyEntity, async (req, next) => {
  // ...
});

[!IMPORTANT] Decorator @OnCreate() will be triggered based on the EntityHandler argument => MyEntity.

[!NOTE] MyEntity was generated using CDS-Typer and imported in the the class.

@OnRead

@OnRead()

Example

import { OnRead, Next } from "@dxfrontier/cds-ts-dispatcher";
import type { TypedRequest, NextEvent } from '@dxfrontier/cds-ts-dispatcher';

import { MyEntity } from 'YOUR_CDS_TYPER_ENTITIES_LOCATION';

@OnRead()
private async onReadMethod(@Req() req: TypedRequest<MyEntity>, @Next() next: NextEvent) {
  // ...

  return next();
}

Equivalent to 'JS'

this.on('READ', MyEntity, async (req, next) => {
  // ...
});

[!IMPORTANT] Decorator @OnRead() will be triggered based on the EntityHandler argument => MyEntity.

[!NOTE] MyEntity was generated using CDS-Typer and imported in the the class.

@OnUpdate

@OnUpdate()

Example


import { OnUpdate, Next } from "@dxfrontier/cds-ts-dispatcher";
import type { TypedRequest, NextEvent } from '@dxfrontier/cds-ts-dispatcher';

import { MyEntity } from 'YOUR_CDS_TYPER_ENTITIES_LOCATION';

@OnUpdate()
private async onUpdateMethod(@Req() req: TypedRequest<MyEntity>, @Next() next: NextEvent) {
  // ...

  return next();
}

Equivalent to 'JS'

this.on('UPDATE', MyEntity, async (req, next) => {
  // ...
});

[!IMPORTANT] Decorator @OnUpdate() will be triggered based on the EntityHandler argument => MyEntity.

[!NOTE] MyEntity was generated using CDS-Typer and imported in the the class.

@OnDelete

@OnDelete()

Example

import { OnDelete, Next } from "@dxfrontier/cds-ts-dispatcher";
import type { TypedRequest, NextEvent } from '@dxfrontier/cds-ts-dispatcher';

import { MyEntity } from 'YOUR_CDS_TYPER_ENTITIES_LOCATION';

@OnDelete()
private async onDeleteMethod(@Req() req: TypedRequest<MyEntity>, @Next() next: NextEvent) {
  // ...

  return next();
}

Equivalent to 'JS'

this.on('DELETE', MyEntity, async (req, next) => {
  // ...
});

[!IMPORTANT] Decorator @OnDelete() will be triggered based on the EntityHandler argument => MyEntity.

[!NOTE] MyEntity was generated using CDS-Typer and imported in the the class.

@OnAction

@OnAction(name : CdsAction)

Parameters

  • name (CdsAction) : Representing the CDS action defined in the CDS file

Example


import { OnAction, Req, Next } from "@dxfrontier/cds-ts-dispatcher";
import type { ActionRequest, ActionReturn, NextEvent } from '@dxfrontier/cds-ts-dispatcher';

import { AnAction } from 'YOUR_CDS_TYPER_ENTITIES_LOCATION';

@OnAction(AnAction)
private async onActionMethod(@Req() req: ActionRequest<typeof AnAction>, @Next() next: NextEvent): ActionReturn<typeof AnAction> {
  // ...
}

Equivalent to 'JS'

this.on(AnAction, async (req, next) => {
  // ...
});

[!NOTE] AnAction was generated using CDS-Typer and imported in the the class.

[!IMPORTANT]
Decorator @OnAction should be used inside @UnboundActions() class.

@OnFunction

@OnFunction(name : CdsFunction)

Parameters

  • name (CdsFunction) : Representing the CDS action defined in the CDS file.

Example

import { OnFunction, Req, Next } from "@dxfrontier/cds-ts-dispatcher";
import type { ActionRequest, ActionReturn, NextEvent } from '@dxfrontier/cds-ts-dispatcher';

import { AFunction } from 'YOUR_CDS_TYPER_ENTITIES_LOCATION';

@OnFunction(AFunction)
private async onFunctionMethod(@Req() req: ActionRequest<typeof AFunction>, @Next() next: NextEvent): ActionReturn<typeof AFunction> {
  // ...
}

Equivalent to 'JS'

this.on(AFunction, async (req) => {
  // ...
});

[!NOTE] AFunction was generated using CDS-Typer and imported in the the class.

[!IMPORTANT]
Decorator @OnFunction should be used inside @UnboundAction() class.

@OnEvent

@OnEvent(name : CdsEvent)

The @OnEvent decorator facilitates the listening of messages from a message broker.

This decorator is particularly useful in conjunction with the Emit method to handle triggered events.

Parameters

  • name (CdsEvent) : Representing the CDS event defined in the CDS file.

Example

import { OnEvent, Req } from "@dxfrontier/cds-ts-dispatcher";
import type { TypedRequest } from '@dxfrontier/cds-ts-dispatcher';

import { AEvent } from 'YOUR_CDS_TYPER_ENTITIES_LOCATION';

@OnEvent(AEvent)
private async onEventMethod(@Req() req: TypedRequest<AEvent>) {
  // ...
}

Equivalent to 'JS'

this.on('AEvent', async (req) => {
  // ...
});

[!NOTE] > AEvent was generated using CDS-Typer and imported in the the class.

[!IMPORTANT]
Decorator @OnEvent should be used inside @UnboundActions class.

[!TIP] More info can be found at https://cap.cloud.sap/docs/guides/messaging/

@OnError

@OnError()

Use @OnError decorator to register custom error handler.

Error handlers are invoked whenever an error occurs during event processing of all potential events and requests, and are used to augment or modify error messages, before they go out to clients.

Example

import { OnError, Error, Req } from "@dxfrontier/cds-ts-dispatcher";
import type { Request } from '@dxfrontier/cds-ts-dispatcher';

@OnError()
private onError(@Error() err: Error, @Req() req: Request) { // sync func
  err.message = 'New message'
  // ...
}

Equivalent to 'JS'

this.on('error', (err, req) => {
  err.message = 'New message';
  // ...
});

[!IMPORTANT]
Decorator @OnError should be used inside @UnboundActions class.

[!CAUTION] OnError callback are expected to be a sync function, i.e., not async, not returning Promises.

[!TIP] More info can be found at SAP CAP Error

@OnBoundAction

@OnBoundAction(name : CdsAction)

Parameters

  • name (CdsAction) : Representing the CDS action defined in the CDS file.

Example

import { OnBoundAction, Req, Next } from "@dxfrontier/cds-ts-dispatcher";
import type { ActionRequest, ActionReturn, NextEvent } from '@dxfrontier/cds-ts-dispatcher';

import { MyEntity } from 'YOUR_CDS_TYPER_ENTITIES_LOCATION';

@OnBoundAction(MyEntity.actions.AnAction)
private async onActionMethod(@Req() req: ActionRequest<typeof MyEntity.actions.AnAction>, @Next() next: NextEvent): ActionReturn<typeof MyEntity.actions.AnAction> {
  // ...
}

Equivalent to 'JS'

this.on(MyEntity.actions.AnAction, MyEntity, async (req) => {
  // ...
});

[!IMPORTANT] Decorator @OnBoundAction() will be triggered based on the EntityHandler argument => MyEntity.

[!NOTE] MyEntity was generated using CDS-Typer and imported in the the class.

@OnBoundFunction

@OnBoundFunction(name : CdsFunction)

Parameters

  • name (CdsFunction) : Representing the CDS action defined in the CDS file.

Example

import { OnBoundFunction, Req, Next } from "@dxfrontier/cds-ts-dispatcher";
import type { ActionRequest, ActionReturn, NextEvent } from '@dxfrontier/cds-ts-dispatcher';

import { MyEntity } from 'YOUR_CDS_TYPER_ENTITIES_LOCATION';

@OnBoundFunction(MyEntity.actions.AFunction)
private async onFunctionMethod(@Req() req: ActionRequest<typeof MyEntity.actions.AFunction>, @Next() next: NextEvent): ActionReturn<typeof MyEntity.actions.AFunction> {
  // ...
}

Equivalent to 'JS'

this.on(MyEntity.actions.AFunction, MyEntity, async (req) => {
  // ...
});

[!IMPORTANT] Decorator @OnBoundFunction() will be triggered based on the EntityHandler argument => MyEntity.

[!NOTE] MyEntity was generated using CDS-Typer and imported in the the class.

Method-draft entity

Before

Use @BeforeNewDraft(), @BeforeCancelDraft(), @BeforeEditDraft(), @BeforeSaveDraft(), @BeforeCreateDraft(), @BeforeReadDraft(), @BeforeUpdateDraft(), @BeforeDeleteDraft() to register handlers to run before.onhandlers, frequently used for validating user input.

The handlers receive one argument:

  • req of type TypedRequest
@BeforeNewDraft

@BeforeNewDraft()

Use this decorator when you want to validate inputs before a new draft is created.

Example

import { BeforeNewDraft, TypedRequest } from "@dxfrontier/cds-ts-dispatcher";
import type { TypedRequest } from '@dxfrontier/cds-ts-dispatcher';

import { MyEntity } from 'YOUR_CDS_TYPER_ENTITIES_LOCATION';

@BeforeNewDraft()
private async beforeCreateDraftMethod(@Req() req: TypedRequest<MyEntity>) {
  // ...
}

Equivalent to 'JS'

this.before('NEW', MyEntity.drafts, async (req) => {
  // ...
});

[!IMPORTANT] Decorator @BeforeNewDraft() will be triggered based on the EntityHandler argument => MyEntity.

[!NOTE] MyEntity was generated using CDS-Typer and imported in the the class.

@BeforeCancelDraft

@BeforeCancelDraft()

Use this decorator when you want to validate inputs before a draft is discarded.

Example

import { BeforeCancelDraft } from "@dxfrontier/cds-ts-dispatcher";
import type { TypedRequest } from '@dxfrontier/cds-ts-dispatcher';

import { MyEntity } from 'YOUR_CDS_TYPER_ENTITIES_LOCATION';

@BeforeCancelDraft()
private async beforeCancelDraftMethod(@Req() req: TypedRequest<MyEntity>) {
  // ...
}

Equivalent to 'JS'

this.before('CANCEL', MyEntity.drafts, async (req) => {
  // ...
});

[!IMPORTANT] Decorator @BeforeCancelDraft() will be triggered based on the EntityHandler argument => MyEntity.

[!NOTE] MyEntity was generated using CDS-Typer and imported in the the class.

@BeforeEditDraft

@BeforeEditDraft()

Use this decorator when you want to validate inputs when a new draft is created from an active instance.

Example

import { BeforeEditDraft } from "@dxfrontier/cds-ts-dispatcher";
import type { TypedRequest } from '@dxfrontier/cds-ts-dispatcher';

import { MyEntity } from 'YOUR_CDS_TYPER_ENTITIES_LOCATION';

@BeforeEditDraft()
private async beforeEditDraftMethod(@Req() req: TypedRequest<MyEntity>) {
  // ...
}

Equivalent to 'JS'

this.before('EDIT', MyEntity, async (req) => {
  // ...
});

[!IMPORTANT] Decorator @BeforeEditDraft() will be triggered based on the EntityHandler argument => MyEntity.

[!NOTE] MyEntity was generated using CDS-Typer and imported in the the class.

@BeforeSaveDraft

@BeforeSaveDraft()

Use this decorator when you want to validate inputs when active entity is changed.

Example

import { BeforeSaveDraft } from "@dxf