jovo-plugin-class-handler
Version:
Jovo plugin that allows using classes for defining handlers.
308 lines (244 loc) • 10.1 kB
Markdown
# jogo-plugin-class-handler
Allows defining classes which serve as handlers via decorators.
## Examples
> Handler: `root.handler.ts`
```typescript
import {Handler, InputData, Intent, Session} from 'jovo-plugin-class-handler';
import {Input, Jovo} from 'jovo-core';
@Handler()
export class RootHandler {
@Intent()
LAUNCH(jovo: Jovo) {
return jovo.toIntent('HelloWorldIntent');
}
@Intent()
HelloWorldIntent(jovo: Jovo) {
jovo.$session.$data.example = 'nice to meet you!';
jovo.ask('Hello World! What\'s your name?', 'Please tell me your name.');
}
@Intent()
MyNameIsIntent(jovo: Jovo, @InputData('name') name: Input, @Session('example') example: string) {
jovo.tell(`Hey ${name.value}, ${example || 'no session data passed.'}`);
}
}
```
or
```typescript
import {BaseHandler, Data, Handler, Intent} from 'jovo-plugin-class-handler';
@Handler({state: 'example'})
export class ExampleHandler extends BaseHandler {
@Intent({name: 'TestIntent'})
someMethodName(@Data('example') example: string) {
this.tell(example || 'no request-data passed.');
}
}
```
## Table of Contents
- [jogo-plugin-class-handler](#jogo-plugin-class-handler)
* [Examples](#examples)
* [Getting Started](#getting-started)
+ [Prerequisites](#prerequisites)
+ [Installation](#installation)
+ [Configuration](#configuration)
- [Example](#example)
* [Usage](#usage)
+ [Handler](#handler)
- [Handler - State](#handler---state)
- [Handler - alternative way to access the Jovo object](#handler---alternative-way-to-access-the-jovo-object)
+ [Intent](#intent)
+ [Data-Decorators](#data-decorators)
* [API](#api)
+ [@Handler(options?: HandlerOptions | string)](#-handler-options---handleroptions---string-)
- [BaseHandler](#basehandler)
- [Parameter options](#parameter-options)
+ [@Intent(options?: IntentOptions | string)](#-intent-options---intentoptions---string-)
- [Parameter options](#parameter-options-1)
+ [Data Decorators](#data-decorators)
- [@Data(key?: string) / @RequestData(key?: string)](#-data-key---string-----requestdata-key---string-)
- [@Session(key?: string) / @SessionData(key?: string)](#-session-key---string-----sessiondata-key---string-)
- [@User(key?: string) / @UserData(key?: string)](#-user-key---string-----userdata-key---string-)
- [@AppData(key?: string)](#-appdata-key---string-)
- [@InputData(key?: string)](#-inputdata-key---string-)
* [Roadmap](#roadmap)
## Getting Started
These instructions will get you the plugin installed and ready to be used.
### Prerequisites
* `typescript` v3.8 or newer
* [jovo/jovo-framework](https://github.com/jovotech/jovo-framework) v3.0 or newer
### Installation
```sh
$ npm install jovo-plugin-class-handler --save
```
> Make sure that `experimentalDecorators` and `emitDecoratorMetadata` are set to `true` in the `tsconfig.json`
In your `app.ts`:
```typescript
import {JovoClassHandler} from 'jovo-plugin-class-handler';
const app = new App();
app.use(
// ...
new JovoClassHandler(),
);
```
### Configuration
You need to setup a configuration for the plugin in the `config.ts` in order for the plugin to detect all handlers.
#### Example
> This configuration assumes that all handlers follow the pattern: (name).handler.(ts or js).
In your `config.ts`:
```typescript
const config = {
// ...
plugin: {
JovoClassHandler: {
handlers: [
__dirname + '/**/*.handler.{ts,js}',
],
},
},
// ...
}
```
Parts of `handlers` can be a string like in the example above (regex is supported), but also a direct import:
```typescript
import RootHandler from './handlers/root.handler';
const config = {
// ...
plugin: {
JovoClassHandler: {
handlers: [
RootHandler,
],
},
},
// ...
}
```
## Usage
After following the installation the plugin is usable. \
You can find a working example in the github-repository in the `example` folder.
### Handler
To get started, create a new Typescript file and export a class and annotate it with `@Handler`. \
The class could look like this:
```typescript
import {Handler} from 'jovo-plugin-class-handler';
@Handler()
export class RootHandler {
}
```
> The first parameter of a `@Intent` decorated method is always a `Jovo`-object if the handler is defined this way.
#### Handler - State
Additionally you can set the state of the handler:
```typescript
import {Handler} from 'jovo-plugin-class-handler';
@Handler('example')
export class ExampleHandler {
}
```
#### Handler - alternative way to access the Jovo object
You can also define a handler the following way:
```typescript
import {BaseHandler, Data, Handler, Intent} from 'jovo-plugin-class-handler';
@Handler({state: 'example'})
export class ExampleHandler extends BaseHandler {
@Intent({name: 'TestIntent'})
someMethodName(@Data('example') example: string) {
this.tell(example || 'no request-data passed.');
}
}
```
> If you define a handler this way, you have access to the `Jovo`-object via `this`.
For more information look at the [API here](#api-handler)
### Intent
After you have defined a handler you can define the intents. For that you have to annotate a method with `@Intent`. \
Here is an example:
```typescript
import {Handler, Intent} from 'jovo-plugin-class-handler';
import {Jovo} from 'jovo-core';
@Handler()
export class RootHandler {
@Intent()
LAUNCH(jovo: Jovo) {
return jovo.toIntent('HelloWorldIntent');
}
@Intent('HelloWorldIntent')
differentName(jovo: Jovo) {
jovo.ask('Hello World! What\'s your name?', 'Please tell me your name.');
}
@Intent({name: 'MyNameIsIntent'})
anotherDifferentName(jovo: Jovo, ) {
jovo.tell(`Hey ... ${jovo.$inputs.name.value}`);
}
}
```
For more information look at the [API here](#api-intent)
### Data-Decorators
You can decorate `@Intent`-annotated methods with parameter decorators that bind data of the `Jovo`-object to the corresponding parameter.
Decorator | Binds ...
--- | ---
`@Data(key?: string)` / `@RequestData(key?: string)` | `$data` / `$data.{key}`
`@Session(key?: string)` / `@SessionData(key?: string)` | `$session.$data` / `$session.$data.{key}`
`@User(key?: string)` / `@UserData(key?: string)` | `$user.$data` / `$user.$data.{key}`
`@AppData(key?: string)` | `$app.$data` / `$app.$data.{key}`
`@InputData(key?: string)` | `$inputs` / `$inputs.{key}`
Example:
```typescript
import {Handler, InputData, Intent, Session} from 'jovo-plugin-class-handler';
import {Input, Jovo} from 'jovo-core';
@Handler()
export class RootHandler {
@Intent()
LAUNCH(jovo: Jovo) {
return jovo.toIntent('HelloWorldIntent');
}
@Intent()
HelloWorldIntent(jovo: Jovo) {
jovo.$session.$data.example = 'nice to meet you!';
jovo.ask('Hello World! What\'s your name?', 'Please tell me your name.');
}
@Intent()
MyNameIsIntent(jovo: Jovo, @InputData('name') name: Input, @Session('example') example: string) {
jovo.tell(`Hey ${name.value}, ${example || 'no session data passed.'}`);
}
}
```
<a name="api"></a>
## API
<a name="api-handler"></a>
### @Handler(options?: HandlerOptions | string)
> `HandlerOptions`: `{state?: string}`
#### BaseHandler
The `BaseHandler`-class is just a wrapper that extends the `Jovo`-class and gets it's value injected at runtime. \
If a `@Handler` decorated class extends the `BaseHandler` all properties and methods of the `Jovo` object are accessible via `this`.
#### Parameter options
* if no `options`: The handler's state will be stateless.
* if `options` of type `string`: The handler's state will be set to `options`.
* if `options` of type `HandlerOptions` and `state`: The handler's state will be set to `options.state`.
* if `options` of type `HandlerOptions` and no `state`: The handler will be stateless
---
<a name="api-intent"></a>
### @Intent(options?: IntentOptions | string)
> `IntentOptions`: `{name?: string}`
> Attention! The first parameter always is the `Jovo`-object for a method that is decorated with `@Intent` if the handler does not extend `BaseHandler`.
#### Parameter options
* if no `options`: The intent's name will be the annotated method's name.
* if `options` of type `string`: The intent's name will be set to `options`.
* if `options` of type `HandlerOptions` and `state`: The intent's name will be set to `options.name`.
* if `options` of type `HandlerOptions` and no `state`: The intent's name will be the method's name
---
<a name="api-data-decorators"></a>
### Data Decorators
> The first parameter of a `@Intent` decorated method is reserved for the `Jovo`-object if the handler-class does not extend `BaseHandler`.
#### @Data(key?: string) / @RequestData(key?: string)
Binds `$data` or `$data.{key}` if key is given.
#### @Session(key?: string) / @SessionData(key?: string)
Binds `$session.$data` or `$session.$data.{key}` if key is given.
#### @User(key?: string) / @UserData(key?: string)
Binds `$user.$data` or `$user.$data.{key}` if key is given.
#### @AppData(key?: string)
Binds `$app.$data` or `$app.$data.{key}` if key is given.
#### @InputData(key?: string)
Binds `$inputs` or `$inputs.{key}` if key is given.
## Roadmap
All listed points have no specific order:
* ~~Parameter decorator to inject data from the `Jovo`-object, example: `@Session(key?: string)` or `@SessionData(key?: string)`.~~
* ~~Find & Implement a way to allow access to `Jovo` context in class to allow calls in vanilla handlers like `this.tell(...)`.~~
* Implement validation for data and/or input