Yoctol / bottender

⚡️ A framework for building conversational user interfaces.
https://bottender.js.org
MIT License
4.23k stars 335 forks source link

Custom NestJS Integration #834

Open florianmaxim opened 4 years ago

florianmaxim commented 4 years ago

I'm curious if anyone has tried to integrate bottender on a custom NestJS server ?..

dcsan commented 4 years ago

@florianmaxim did you proceed with this? nest is very heavily typescript focused, i hit some issues with that

florianmaxim commented 4 years ago

Works like a charm!

import { NestFactory } from '@nestjs/core';
import { ExpressAdapter } from '@nestjs/platform-express';

import express from 'express';
import bodyParser from 'body-parser';
import { bottender } from 'bottender';

import { AppModule } from './app.module';

var cors = require('cors')

const app = bottender({ dev: true });

const handle = app.getRequestHandler();

async function bootstrap() {

  const server = express();

  server.get('/hello', async (req, res) => {
    res.send('hi')
  });

  server.enable('trust proxy');

  const verify = (req, _, buf) => {
    req.rawBody = buf.toString();
  };

  server.use(cors());

  server.use(bodyParser.json({ verify }));
  server.use(bodyParser.urlencoded({ extended: false, verify }));
  server.use((req, res, next) => {
    //TODO: Twilio workaround: https://github.com/Yoctol/bottender/issues/815
    if(req.originalUrl === '/webhooks/whatsapp') {
      req.url = `/api${req.url}`;
    }
    // console.log('requestUrl', `${req.protocol}://${req.hostname}${req.url}`);
    next();
  });

  // Handle webhook requests
  server.all('/webhooks/*', (req, res) => {
    return handle(req, res);
  });

  const app = await NestFactory.create(
    AppModule,
    new ExpressAdapter(server),
  );
  await app.init();
  await app.listen(3000);
};

app.prepare().then(async () => {
  await bootstrap();
});

Trying to figure out how to integrate NestJS Injection concept into Bottender. Would be amazing to be able to use services like this:

class QuestionsHandler {
  constructor(
    private userService: UserService,
  ) {
    return router([
      text(['How old am I?'], this.userService.getAge()),
    ])
  }
}
zsevic commented 4 years ago

@florianmaxim it is possible to do something similar

// index.ts
export default async function App() {
  const app = await application.get();
  const chatbotService = app
    .select(ChatbotModule)
    .get(ChatbotService, { strict: true });

  return chatbotService.getRouter();
}
// chatbot.service.ts
getRouter = () => router([platform('messenger', this.handleMessenger)]);

private handleMessenger = () =>
  router([
    messenger.message(this.controller.messageHandler)),
    messenger.postback(this.controller.postbackHandler)),
  ]);
// chatbot.controller.ts
messageHandler = async (context: MessengerContext) => {};
postbackHandler = async (context: MessengerContext) => {};

here is the repo with full codebase https://github.com/zsevic/chatbot-starter