Botkit With Express - express

The documentation at Botkit (https://github.com/howdyai/botkit/blob/master/readme-facebook.md) is pretty not meaningful at all:
// if you are already using Express, you can use your own server instance...
// see "Use BotKit with an Express web server"
controller.setupWebserver(process.env.port,function(err,webserver) {
controller.createWebhookEndpoints(controller.webserver, bot, function() {
console.log('This bot is online!!!');
});
});
Moreover, without a custom webserver (like express), Botkit doesnt provide a way to set the custom local url (instead, it simply chooses 0.0.0.0, which is impractical).
Is anyone successfully assembling app = require('express')(); into the setupWebserver in Botkit (specially for Messenger). If yes, please present the full code.

Hostname for the built in express server can be set when creating your controller:
var controller = Botkit.facebookbot({
hostname: 'YOUR_HOST_NAME',
verify_token: '',
access_token: ''
})
controller.setupWebserver and controller.createWebhookEndpoints are helper functions within botkit to do just what they describe, create an express webserver and webhook endpoints, respectively.
To implement your own webserver, you just need to setup a webhook endpoint for the botkit controller to receive message POST data at and perform auth handshakes.
By botkit convention this is /{platform}/receive so for facebook /facebook/receive but you can use whatever you like.
To use a custom express server with Botkit, first create a basic webserver.
// components/express_webserver.js
var express = require('express');
var bodyParser = require('body-parser');
var querystring = require('querystring');
var debug = require('debug')('botkit:webserver');
module.exports = function(controller, bot) {
var webserver = express();
webserver.use(bodyParser.json());
webserver.use(bodyParser.urlencoded({ extended: true }));
webserver.use(express.static('public'));
// You can pass in whatever hostname you want as the second argument
// of the express listen function, it defaults to 0.0.0.0 aka localhost
webserver.listen(process.env.PORT || 3000, null, function() {
console.log('Express webserver configured and listening at ',
process.env.HOSTNAME || 'http://localhost/' + ':' + process.env.PORT || 3000);
});
// Register our routes, in this case we're just using one route
// for all incoming requests from FB
// We are passing in the webserver we created, and the botkit
// controller into our routes file so we can extend both of them
require('./routes/incoming-webhook')(webserver, controller)
controller.webserver = webserver;
return webserver;
}
Next you need to create the routes for webhook endpoints, we're doing this in a separate file as is common with express
// components/routes/webhook.js
module.exports = function(webserver, controller) {
// Receive post data from fb, this will be the messages you receive
webserver.post('/facebook/receive', function(req, res) {
// respond to FB that the webhook has been received.
res.status(200);
res.send('ok');
var bot = controller.spawn({});
// Now, pass the webhook into be processed
controller.handleWebhookPayload(req, res, bot);
});
// Perform the FB webhook verification handshake with your verify token
webserver.get('/facebook/receive', function(req, res) {
if (req.query['hub.mode'] == 'subscribe') {
if (req.query['hub.verify_token'] == controller.config.verify_token) {
res.send(req.query['hub.challenge']);
} else {
res.send('OK');
}
}
});
}
Once you have created these two files, you will use require and pass your controller into the express module. Your main bot file should look something like this
// bot.js
var Botkit = require('botkit');
// Create the Botkit controller, which controls all instances of the bot.
var controller = Botkit.facebookbot({
debug: true,
verify_token: process.env.verify_token,
access_token: process.env.page_token,
});
// Set up an Express-powered webserver to expose oauth and webhook endpoints
// We are passing the controller object into our express server module
// so we can extend it and process incoming message payloads
var webserver = require(__dirname + '/components/express_webserver.js')(controller);

You can find in github a, MIT-licensed, full Demo of running BotKit for Facebook Messenger on an Express server with MongoDB storage.
Here is the main server.js
// modules =================================================
var express = require('express') // framework d'appli
var app = express()
var bodyParser = require('body-parser') // BodyParser pour POST
var http = require('http').Server(app) // préparer le serveur web
var dotenv = require('dotenv')
var path = require('path')
// configuration ===========================================
// load environment variables,
// either from .env files (development),
// heroku environment in production, etc...
dotenv.load()
app.use(express.static(path.join(__dirname, '/public')))
// parsing
app.use(bodyParser.json()) // for parsing application/json
app.use(bodyParser.urlencoded({ extended: true })) // for parsing url encoded
// view engine ejs
app.set('view engine', 'ejs')
// routes
require('./app/routes/routes')(app)
// port for Heroku
app.set('port', (process.env.PORT || 5000))
// START ===================================================
http.listen(app.get('port'), function () {
console.log('listening on port ' + app.get('port'))
})

okay so here goes i was trying the same thing and have been able to start the botkit up with a custom url on express. You dont have to worry about this code at all:
controller.setupWebserver(process.env.port,function(err,webserver) {
controller.createWebhookEndpoints(controller.webserver, bot, function() {
console.log('This bot is online!!!');
});
});
This repository has its own code with will work with a mongodb database and a express server.
git clone https://github.com/mvaragnat/botkit-messenger-express-demo.git
sudo npm install express --save
sudo npm link body-parser
sudo npm link dotenv
sudo npm install --save botkit
sudo npm install --save monkii
sudo npm install --save mongodb
sudo npm install --save request
sudo npm install --save ejs
In all of the above steps you can perform:
sudo npm link botkit
etc
Finally run node server.js
lt --subdomain botkit --port 5000
restart node server.js
Dont Forget to add your variables to .env file in the directory.
All your traffic on local host will be redirected to the localtunnel, you can get a url using the lt --subdomain name --port 5000
Use this generated url in the webhooks on your page and your bot should be online.

Related

Cors issue solved by using proxy not working after served in Netlify Create-react-app

I have built a real estate site that makes a an api request to "https://completecriminalchecks.com" In development mode I was getting the dreaded blocked by Cors error. Through some research I found that I needed to use a proxy to solve the issue, which it did in development mode on my local host. But now I have deployed the site to netlify, I am getting a 404 error when making the request. when I look at the request from the network devtools its says
Request URL: https://master--jessehaven.netlify.app/api/json/?apikey=6s4xxxxx13xlvtphrnuge19&search=radius&miles=2&center=98144
I dont think this is right. How do i make netlify make the proper request to the api that was having cors issues in development?
Have you tried netify documentation about it?
Proxy to another service Just like you can rewrite paths like /* to
/index.html, you can also set up rules to let parts of your site proxy
to external services. Let's say you need to communicate from a
single-page app with an API on https://api.example.com that doesn't
support CORS requests. The following rule will let you use /api/ from
your JavaScript client:
/api/* https://api.example.com/:splat 200
Now all requests to /api/... will be proxied through to
https://api.example.com straight from our CDN servers without an
additional connection from the browser. If the API supports standard
HTTP caching mechanisms like ETags or Last-Modified headers, the
responses will even get cached by our CDN nodes.
You do not need to use a proxy, you enable CORRS in your server. Are you using a onde server?
If you use express something like this:
npm install --save cors
And then use it as middleware:
var express = require('express');
var cors = require('cors');
var app = express();
app.use(cors());
Also in your netlify.toml file this will do the trick:
# The following redirect is intended for use with most SPAs that handle
# routing internally.
[[redirects]]
from = "/*"
to = "/index.html"
status = 200
[[headers]]
# Define which paths this specific [[headers]] block will cover.
for = "/*"
[headers.values]
Access-Control-Allow-Origin = "*"
I also faced the same issue and solved by creating a netlify.toml file in root directory.
Here is a sample code for redirect which worked for me.
Place this inside the netlify.toml file.
Documentation guide for proxy :
[[redirects]]
from = "/api/users/tickets/"
to = "https://some-external-site.com/api/users/tickets/"
status = 200
force = true
headers = {Access-Control-Allow-Origin = "*"}
[[redirects]]
from = "/api/users/cars/*"
to = "https://some-external-site.com/api/users/cars/:splat"
status = 200
force = true
headers = {Access-Control-Allow-Origin = "*"}
I also faced the same issue , so I removed the "proxy" from the "package.json" file and created a variable to store the IP addess or URL for backend , then used it with the URL parameter for calling API. The CORS issue is solved in backend by allowing "All origins".
File to store base URL:
constant.js :
export const baseUrl = "https://backEndUrl";
File to call API:
getDataApi.js:
import { baseUrl } from "./constant";
export const getProfileData = () => (dispatch) => {
axios
.get(`${baseUrl }/api/profile`)
.then((res) =>
dispatch({
type: GET_PROFILE,
payload: res.data,
})
)
.catch((err) =>
dispatch({
type: GET_PROFILE,
payload: null,
})
);
};

How to set custom port number on swagger-api?

I created the project using the following command and chose Express framework.
swagger project create api-name
project starts on http://localhost:10010/
But I set my custom port number 10020.
Starting: /home/rajan/Documents/cse-4-1/web-lab/api/BankApi/app.js...
project started here: http://localhost:10010/
project will restart on changes.
to restart at any time, enter `rs`
try this:
curl http://127.0.0.1:10020/hello?name=Scott
My question is why second and last line showing different port number?
My app.js file:
'use strict';
var SwaggerExpress = require('swagger-express-mw');
var app = require('express')();
module.exports = app; // for testing
var config = {
appRoot: __dirname // required config
};
SwaggerExpress.create(config, function(err, swaggerExpress) {
if (err) { throw err; }
// install middleware
swaggerExpress.register(app);
//var port = process.env.PORT || 10010;
var port = 10020;
app.listen(port);
if (swaggerExpress.runner.swagger.paths['/hello']) {
console.log('try this:\ncurl http://127.0.0.1:' + port + '/hello?name=Scott');
}
});
I also set the port number on yaml file. Then fixed it.

socket.io.js not found (404)

I am referring to an issue that has been asked many times but the solutions posted elsewhere are not resolving my problem ie socket.io.js not found.
The error message is
GET http://127.0.0.1:3000/socket.io/socket.io.js 404
Any help would be appreciated.
I referenced socket.io.js in my JADE file:
script(src='http://code.jquery.com/jquery.js')
script(src='http://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/js/bootstrap.min.js')
script(src='/socket.io/socket.io.js')
script(src='/javascripts/sockets/client.js') // this is in public folder
In my App.js file:
var express = require('express');
io = require('socket.io');
http = require('http');
app = express();
server = http.createServer(app);
io = io.listen(server);
server.listen(app.get('port'), function(){
console.log("Express server listening on port " + app.get('port'));
});
app.use(express.static(path.join(__dirname, 'public')));
These are the versions I am using:
"express": "~4.13.1",
"jade": "~1.11.0",
"morgan": "~1.6.1",
"serve-favicon": "~2.3.0",
"socket.io": "0.9.10"
Some additional info:
In my app.js: I referenced the server socket
// set up our socket server
require('./public/javascripts/sockets/server')(io);
'/javascripts/sockets/client.js' is my client socket:
var socket = io.connect('/');
socket.on('message', function (data) {
data = JSON.parse(data);
$('#messages').append('<div class="'+data.type+'">' + data.message +
'</div>');
});
$(function(){
$('#send').click(function(){
var data = {
message: $('#message').val(),
type:'userMessage'
};
socket.send(JSON.stringify(data));
$('#message').val('');
});
You shouldn't be using the socket.io package for this as it is primarily intended to construct a socket.io server instance. Instead you should be using socket.io-client which was specifically made to be used as the client socket.
I would recommend using bower to install this instead of npm as bower is made for front-end package management. Inside your project directory execute the following
note: If you don't have bower installed you'll need to install it globally npm i -g bower
bower init
bower install --save socket.io-client
Then you should make the bower_components directory created by installing the socket.io-client a static directory
server.use(express.static(path.join(__dirname, 'bower_components')));
Then change
script(src='/javascripts/sockets/client.js') // this is in public folder
to
script(src='/bower_components/socket.io-client)
Additionally, you're mixing your server and app variables. You should be using whatever variable your socket.io was created using, in this case you're using server so you should be using that. Your server file is mostly incorrect as you're instantiating many global values and you've created your io instance incorrectly.
var express = require('express');
var app = express();
var server = require('http').Server(app);
var io = require('socket.io')(server);
var port = process.env.PORT || 3000;
server.use(express.static(path.join(__dirname, 'public')));
server.use(express.static(path.join(__dirname, 'bower_components')));
server.listen(port, function(){
console.log('Express server listening on port ' + port);
});

Node express server, CORS API restriction, including an entry in my development machine’s hosts file

I am trying to use an API that has an API CORS policy that does not support browser requests from any domain. In order to allow clientside JavaScript code to access the API, whilst developing my application, I have been advised to I serve my webapp from '*.thisCompany.com' domain.
It was advised to include an entry in my development machine’s hosts file, as follows, which I have done:
$ echo '127.0.0.1 localhost.thisCompany.com' >> /etc/hosts
Following this command when I run sudo nano /private/etc/hosts
this is the screen that I see.
Host Database
localhost is used to configure the loopback interface
when the system is booting. Do not change this entry.
127.0.0.1 localhost
127.0.0.1 localhost.thisCompany.com
And then I have been told that I should be able access my webapp at http://localhost.thisCompany.com.
I am using node express as my server and the code in my server.js file looks like this
var express = require('express');
var server = express();
var path = require('path');
var port = process.env.PORT || 'thisCompany.com';
server.use(express.static(__dirname + '/public'));
server.use('/bower_components', express.static(__dirname + '/bower_components'));
server.get('/', function(request, response) {
response.sendFile(path.join(__dirname + '/views/index.html'));
});
server.listen(port, function() {
console.log("Node app is running at localhost:" + port)
});
Can anyone advise what steps I should follow to enable me to call this API and bypass the API CORS policy?
I have read various other posts here, and also other articles online, however I cannot find the solution. Really hoping someone on this can help.
Thanks, Paul
I misunderstood how I was supposed to view a page locally on my computer after amending the hosts file on my local machine. I didn't need to add anything to my express server. The express server code remained as follows:
var express = require('express');
var server = express();
var path = require('path');
var port = process.env.PORT || 3000;
server.use(express.static(__dirname + '/public'));
server.use('/bower_components', express.static(__dirname + '/bower_components'));
server.get('/', function(request, response) {
response.sendFile(path.join(__dirname + '/views/index.html'));
});
server.listen(port, function() {
console.log("Node app is running at localhost:" + port)
});
After adding the line mentioned in my original post to my hosts file on my local machine, I then needed to launch my server and access the page by following this link.
http://localhost.thisCompany.com:3000/
Although this is quite a niche issue, I hope this post helps someone in the future.

Socket.IO Authentication

I am trying to use Socket.IO in Node.js, and am trying to allow the server to give an identity to each of the Socket.IO clients. As the socket code is outside the scope of the http server code, it doesn't have easy access to the request information sent, so I'm assuming it will need to be sent up during the connection. What is the best way to
1) get the information to the server about who is connecting via Socket.IO
2) authenticate who they say they are (I'm currently using Express, if that makes things any easier)
Use connect-redis and have redis as your session store for all authenticated users. Make sure on authentication you send the key (normally req.sessionID) to the client. Have the client store this key in a cookie.
On socket connect (or anytime later) fetch this key from the cookie and send it back to the server. Fetch the session information in redis using this key. (GET key)
Eg:
Server side (with redis as session store):
req.session.regenerate...
res.send({rediskey: req.sessionID});
Client side:
//store the key in a cookie
SetCookie('rediskey', <%= rediskey %>); //http://msdn.microsoft.com/en-us/library/ms533693(v=vs.85).aspx
//then when socket is connected, fetch the rediskey from the document.cookie and send it back to server
var socket = new io.Socket();
socket.on('connect', function() {
var rediskey = GetCookie('rediskey'); //http://msdn.microsoft.com/en-us/library/ms533693(v=vs.85).aspx
socket.send({rediskey: rediskey});
});
Server side:
//in io.on('connection')
io.on('connection', function(client) {
client.on('message', function(message) {
if(message.rediskey) {
//fetch session info from redis
redisclient.get(message.rediskey, function(e, c) {
client.user_logged_in = c.username;
});
}
});
});
I also liked the way pusherapp does private channels.
A unique socket id is generated and
sent to the browser by Pusher. This is
sent to your application (1) via an
AJAX request which authorizes the user
to access the channel against your
existing authentication system. If
successful your application returns an
authorization string to the browser
signed with you Pusher secret. This is
sent to Pusher over the WebSocket,
which completes the authorization (2)
if the authorization string matches.
Because also socket.io has unique socket_id for every socket.
socket.on('connect', function() {
console.log(socket.transport.sessionid);
});
They used signed authorization strings to authorize users.
I haven't yet mirrored this to socket.io, but I think it could be pretty interesting concept.
I know this is bit old, but for future readers in addition to the approach of parsing cookie and retrieving the session from the storage (eg. passport.socketio ) you might also consider a token based approach.
In this example I use JSON Web Tokens which are pretty standard. You have to give to the client page the token, in this example imagine an authentication endpoint that returns JWT:
var jwt = require('jsonwebtoken');
// other requires
app.post('/login', function (req, res) {
// TODO: validate the actual user user
var profile = {
first_name: 'John',
last_name: 'Doe',
email: 'john#doe.com',
id: 123
};
// we are sending the profile in the token
var token = jwt.sign(profile, jwtSecret, { expiresInMinutes: 60*5 });
res.json({token: token});
});
Now, your socket.io server can be configured as follows:
var socketioJwt = require('socketio-jwt');
var sio = socketIo.listen(server);
sio.set('authorization', socketioJwt.authorize({
secret: jwtSecret,
handshake: true
}));
sio.sockets
.on('connection', function (socket) {
console.log(socket.handshake.decoded_token.email, 'has joined');
//socket.on('event');
});
The socket.io-jwt middleware expects the token in a query string, so from the client you only have to attach it when connecting:
var socket = io.connect('', {
query: 'token=' + token
});
I wrote a more detailed explanation about this method and cookies here.
Here is my attempt to have the following working:
express: 4.14
socket.io: 1.5
passport (using sessions): 0.3
redis: 2.6 (Really fast data structure to handle sessions; but you can use others like MongoDB too. However, I encourage you to use this for session data + MongoDB to store other persistent data like Users)
Since you might want to add some API requests as well, we'll also use http package to have both HTTP and Web socket working in the same port.
server.js
The following extract only includes everything you need to set the previous technologies up. You can see the complete server.js version which I used in one of my projects here.
import http from 'http';
import express from 'express';
import passport from 'passport';
import { createClient as createRedisClient } from 'redis';
import connectRedis from 'connect-redis';
import Socketio from 'socket.io';
// Your own socket handler file, it's optional. Explained below.
import socketConnectionHandler from './sockets';
// Configuration about your Redis session data structure.
const redisClient = createRedisClient();
const RedisStore = connectRedis(Session);
const dbSession = new RedisStore({
client: redisClient,
host: 'localhost',
port: 27017,
prefix: 'stackoverflow_',
disableTTL: true
});
// Let's configure Express to use our Redis storage to handle
// sessions as well. You'll probably want Express to handle your
// sessions as well and share the same storage as your socket.io
// does (i.e. for handling AJAX logins).
const session = Session({
resave: true,
saveUninitialized: true,
key: 'SID', // this will be used for the session cookie identifier
secret: 'secret key',
store: dbSession
});
app.use(session);
// Let's initialize passport by using their middlewares, which do
//everything pretty much automatically. (you have to configure login
// / register strategies on your own though (see reference 1)
app.use(passport.initialize());
app.use(passport.session());
// Socket.IO
const io = Socketio(server);
io.use((socket, next) => {
session(socket.handshake, {}, next);
});
io.on('connection', socketConnectionHandler);
// socket.io is ready; remember that ^this^ variable is just the
// name that we gave to our own socket.io handler file (explained
// just after this).
// Start server. This will start both socket.io and our optional
// AJAX API in the given port.
const port = 3000; // Move this onto an environment variable,
// it'll look more professional.
server.listen(port);
console.info(`🌐 API listening on port ${port}`);
console.info(`🗲 Socket listening on port ${port}`);
sockets/index.js
Our socketConnectionHandler, I just don't like putting everything inside server.js (even though you perfectly could), especially since this file can end up containing quite a lot of code pretty quickly.
export default function connectionHandler(socket) {
const userId = socket.handshake.session.passport &&
socket.handshake.session.passport.user;
// If the user is not logged in, you might find ^this^
// socket.handshake.session.passport variable undefined.
// Give the user a warm welcome.
console.info(`⚡︎ New connection: ${userId}`);
socket.emit('Grettings', `Grettings ${userId}`);
// Handle disconnection.
socket.on('disconnect', () => {
if (process.env.NODE_ENV !== 'production') {
console.info(`⚡︎ Disconnection: ${userId}`);
}
});
}
Extra material (client):
Just a very basic version of what the JavaScript socket.io client could be:
import io from 'socket.io-client';
const socketPath = '/socket.io'; // <- Default path.
// But you could configure your server
// to something like /api/socket.io
const socket = io.connect('localhost:3000', { path: socketPath });
socket.on('connect', () => {
console.info('Connected');
socket.on('Grettings', (data) => {
console.info(`Server gretting: ${data}`);
});
});
socket.on('connect_error', (error) => {
console.error(`Connection error: ${error}`);
});
References:
I just couldn't reference inside the code, so I moved it here.
1: How to set up your Passport strategies: https://scotch.io/tutorials/easy-node-authentication-setup-and-local#handling-signupregistration
This article (http://simplapi.wordpress.com/2012/04/13/php-and-node-js-session-share-redi/) shows how to
store sessions of the HTTP server in Redis (using Predis)
get these sessions from Redis in node.js by the session id sent in a cookie
Using this code you are able to get them in socket.io, too.
var io = require('socket.io').listen(8081);
var cookie = require('cookie');
var redis = require('redis'), client = redis.createClient();
io.sockets.on('connection', function (socket) {
var cookies = cookie.parse(socket.handshake.headers['cookie']);
console.log(cookies.PHPSESSID);
client.get('sessions/' + cookies.PHPSESSID, function(err, reply) {
console.log(JSON.parse(reply));
});
});
use session and Redis between c/s
Server side
io.use(function(socket, next) {
// get here session id
console.log(socket.handshake.headers.cookie); and match from redis session data
next();
});
this should do it
//server side
io.sockets.on('connection', function (con) {
console.log(con.id)
})
//client side
var io = io.connect('http://...')
console.log(io.sessionid)