/jovo-plugin-class-handler

A Jovo plugin to use classes as handlers for the Jovo Framework

Primary LanguageTypeScript

jovo-plugin-class-handler

Allows defining classes which serve as handlers via decorators.

Examples

Handler: root.handler.ts

import { Input, Jovo } from 'jovo-core';
import { Handler, InputData, Intent, Session } from 'jovo-plugin-class-handler';

@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.'}`);
  }

  @Intent()
  TestIntent(jovo: Jovo) {
    jovo.$data.example = 'Hello this is the request-data example.';
    return jovo.toStateIntent('example', 'TestIntent');
  }

  @Intent()
  NestedTestIntent(jovo: Jovo) {
    return jovo.toStateIntent('some.nested.state', 'TestIntent');
  }
}

or

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

Getting Started

These instructions will get you the plugin installed and ready to be used.

Prerequisites

Installation

$ 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:

import { JovoClassHandler } from 'jovo-plugin-class-handler';

const app = new App();

app.use(
  // ...
  new JovoClassHandler()
);

Handlers previously added by calling app.setHandler(...) will be merged with handlers that were loaded by this plugin! It is recommended to not set any handlers.

Configuration

You need to setup a configuration for the plugin in the config.ts or via the constructor 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:

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:

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:

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:

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:

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

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:

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

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:

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.'}`);
  }
}

API

@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


@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


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.