NestJS and ask SDK service injection

196 Views Asked by At

I'm trying to build a custom Alexa webservice with nestjs. From AlexaController if I try to call a service inside a RequestHandler, it doesn't work because the this. isn't available there ( if I try console.log(this) inside the requestHandler i see {canHandle, handle} ) and the server returns me that the service is undefined. This is my controller:

import { Controller, HttpCode, Post, Req } from "@nestjs/common";
import {
  ErrorHandler,
  HandlerInput,
  RequestHandler,
  SkillBuilders,
} from "ask-sdk-core";
import { Response } from "ask-sdk-model";
import { Request } from "express";
import { MessagesService } from "src/services/messages/messages.service";

@Controller("alexa")
export class AlexaController {
  constructor(private myService: MessagesService) {}

  @Post()
  @HttpCode(200)
  async alexaSkill(@Req() req: Request) {
    let skill = SkillBuilders.custom()
      .addRequestHandlers(
        this.LaunchRequestHandler // welcome
      )
      .addErrorHandlers(this.ErrorHandler)
      .create();

    return skill
      .invoke(req.body)
      .then((res) => {
        return res;
      })
      .catch((err) => {
        console.log(err);
      });
  }

  LaunchRequestHandler: RequestHandler = {
    canHandle(handlerInput: HandlerInput): boolean {
      return handlerInput.requestEnvelope.request.type === "LaunchRequest";
    },
    handle(handlerInput: HandlerInput): Response {
      const speechText = "Welcome to the Alexa Skills Kit, you can say hello!";

      // here I want to call this.myService to do something.
      this.myService.something("hi Alexa");
      // it returns me this error: cannot call something of undefined

      return handlerInput.responseBuilder
        .speak(speechText)
        .reprompt(speechText)
        .withSimpleCard("Hello World", speechText)
        .getResponse();
    },
  };

  ErrorHandler: ErrorHandler = {
    canHandle(handlerInput: HandlerInput, error: Error): boolean {
      return true;
    },
    handle(handlerInput: HandlerInput, error: Error): Response {
      console.log(`Error handled: ${error.message}`);

      return handlerInput.responseBuilder
        .speak("Sorry, I can't understand the command. Please say again.")
        .reprompt("Sorry, I can't understand the command. Please say again.")
        .getResponse();
    },
  };
}

This is my AlexaModule:

import { Module } from "@nestjs/common";
import { MessagesService } from "src/services/messages/messages.service";
import { AlexaController } from "./alexa.controller";

@Module({
  controllers: [AlexaController],
  providers: [MessagesService],
})
export class AlexaModule {}

How can I make the service visible inside that RequestHandler ? Any suggestion ? Thanks in advance

1

There are 1 best solutions below

0
On BEST ANSWER

The this keyword in Javascript can refer to different things depending on the scope of where it's accessed. This is a common source of confusion for Javascript developers and there is a ton of content out there you can read about this scopes if you do a quick Google.

That being said, many of the common errors caused by this are now "solved" since the introduction of arrow functions in Javascript as they will automatically capture the this context from the outer scope which typically is the one you're after.

Try rewriting your handlers using arrow functions instead of using regular functions:

LaunchRequestHandler: RequestHandler = {
        canHandle: (handlerInput: HandlerInput) => {
          return handlerInput.requestEnvelope.request.type === "LaunchRequest";
        },
        handle: (handlerInput: HandlerInput) => {
          const speechText = "Welcome to the Alexa Skills Kit, you can say hello!";
    
          this.myService.something("hi Alexa");
    
          return handlerInput.responseBuilder
            .speak(speechText)
            .reprompt(speechText)
            .withSimpleCard("Hello World", speechText)
            .getResponse();
        },
      };