@dxfrontier/cds-ts-dispatcher v2.0.13
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
- Table of Contents
- Prerequisites
- Installation
- Usage
Deployment
to BTP using MTABest practices
\&tips
Examples
- Contributing
- License
- Authors
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.
- Create new folder :
mkdir new-sap-cap-project
cd new-sap-cap-project
- Initialize the CDS folder structure :
cds init
- Add CDS-Typer to your npm package.json:
cds add typer
npm install
- Add the the following NPM packages :
npm install @dxfrontier/cds-ts-dispatcher
npm install --save-dev @types/node
- Add a tsconfig.json :
tsc --init
- 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"]
}
- 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 developmentCloud MTA Build tool
for buildingMTA file
Cloud Foundry CLI (CF)
Git
,Cds
,Npm
,Node
CDS-Typer
for building typescript entities out ofCDS files
tsconfig.json, .eslintrc, .prettierrc
- predefined propertiespackage.json
- predefinedscripts
Steps
- Install Docker desktop
- Clone CDS-TS-Dispatcher devcontainer using below command :
git clone https://github.com/dxfrontier/cds-ts-dispatcher-dev-container
- Open project in
VSCode
using:
code cds-ts-dispatcher-dev-container
- 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
Install Remote development pack VScode extension
COMMAND + SHIFT + P on
MacOS
or CTRL + SHIFT + P onWindows
- Type -
Rebuild and Reopen in Container
- This step will start creating the container project and start the Node server.
- Type -
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 be reflected 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.
!TIP If above option is being used, you have to run every time the command when you do a change in a
.CDS file
Important
!CAUTION Import always the
generated entities from the service folders and not from the index.ts
For more info see official SAP CDS-Typer page.
Usage
Architecture
We recommend adhering to the Controller-Service-Repository design pattern using the following folder structure:
- EntityHandler
(Controller)
- Responsible for managing the REST interface to the business logic implemented in ServiceLogic - ServiceLogic
(Service)
- Contains business logic implementations - Repository
(Repository)
- This component is dedicated to handling entity manipulation operations by leveraging the power of CDS-QL.
Controller-Service-Repository
suggested folder structure
<= expanded folders =>
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
initialize
: Theinitialize
method of theCDSDispatcher
class is used to initialize Entity handler(s) and all of their dependencies : Services, Repositories, UnboundActions
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 canimport 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 forDependency 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 forDependency 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 specificEntity
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() {}
// ...
}
- Think of it (middleware) like as a reusable class, enhancing the functionality of all events within the class.
- Middlewares when applied with
@Use
are executed before the normal events.- 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 ofRequestResponse
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 RequestBody
.
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 typeError
.
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 retrievedJWT 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: Key, property: PickQueryPropsByKey\)
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 areINSERT
,SELECT
,UPDATE
,UPSERT
,DELETE
.property (string)
: Specifies the property based on thekey
.
Return
boolean
: This decorator returnstrue
ifproperty
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 returnstrue
if at least one of the specified roles is assigned to the current request user, otherwisefalse
.
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 yourCDS
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 returnstrue
ifcolumn
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: Key, property: PickQueryPropsByKey\)
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 areINSERT
,SELECT
,UPDATE
,UPSERT
,DELETE
.property (string)
: Specifies the property based on thekey
.
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(
- @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(
- @GetQuery(
'UPDATE'
,'data'
) data:GetQueryType['data']
- @GetQuery(
'UPDATE'
,'entity'
) entity:GetQueryType['entity']
- @GetQuery(
'UPDATE'
,'where'
) where:GetQueryType['where']
- @GetQuery(
- @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(
- @GetQuery(
'DELETE'
,'from'
) from:GetQueryType['from'][forDelete]
@GetQuery(
'DELETE'
,'where'
) columns:GetQueryType['where']
- @GetQuery(
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 theRequest
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 theRequest
issingle instance
false
when theRequest
isentity 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 typeTypedRequest
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 EntityHandlerargument
=>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 EntityHandlerargument
=>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 EntityHandlerargument
=>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 EntityHandlerargument
=>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 EntityHandlerargument
=>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 EntityHandlerargument
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 EntityHandlerargument
=>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 EntityHandlerargument
=>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 typeTypedRequest
next
of typeNextEvent
!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 EntityHandlerargument
=>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 EntityHandlerargument
=>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 EntityHandlerargument
=>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 EntityHandlerargument
=>MyEntity
.!NOTE MyEntity was generated using CDS-Typer and imported in the the class.
@OnAction
@OnAction(name
: CdsAction)
Parameters
name (CdsAction)
: Representing theCDS action
defined in theCDS 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 theCDS action
defined in theCDS 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 theCDS event
defined in theCDS 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 returningPromises
.!TIP More info can be found at SAP CAP Error
@OnBoundAction
@OnBoundAction(name
: CdsAction)
Parameters
name (CdsAction)
: Representing theCDS action
defined in theCDS 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 EntityHandlerargument
=>MyEntity
.!NOTE MyEntity was generated using CDS-Typer and imported in the the class.
@OnBoundFunction
@OnBoundFunction(name
: CdsFunction)
Parameters
name (CdsFunction)
: Representing theCDS action
defined in theCDS 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 EntityHandlerargument
=>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.on
handlers, frequently used for validating user input.
The handlers receive one argument:
req
of typeTypedRequest
@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 EntityHandlerargument
=>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 EntityHandlerargument
=>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 EntityHandlerargument
=>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 "@dxfrontier/cds-ts-dispatcher";
import type { TypedRequest } from '@dxfrontier/cds-ts-dispatcher';
import
5 days ago
13 days ago
23 days ago
24 days ago
25 days ago
25 days ago
25 days ago
25 days ago
26 days ago
26 days ago
26 days ago
26 days ago
27 days ago
1 month ago
1 month ago
2 months ago
2 months ago
2 months ago
2 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
6 months ago
6 months ago
6 months ago
6 months ago