I have created simple Action-on google project and build Action with dialogflow.
In Dialogflow Intents are "welcome intent" -> follow-up-yes
And then fulfillment enabled (firebase http request) with local development project.
in my local project, I'm trying to call anotherfile(app.js) within index.js(The main file)
Plese tell me how to do that?
index.js
'use strict';
const functions = require('firebase-functions');
const express = require('express');
const bodyParser = require('body-parser');
const app = express();
app.use(bodyParser.urlencoded({extended: true}));
app.use(express.json());
app.use('/', require('./routes/app'));
const helloWorld = functions.https.onRequest(app);
module.exports = {helloWorld};
routes/app.js
const express = require('express');
const router = express.Router();
const {dialogflow} = require('actions-on-google');
const app = dialogflow({debug: true});
app.intent('Welcome-Intent-yes', (conv, param) => {
conv.close('Plese login ');
});
router.use(app);
module.exports = router;
-------- edited info ------
This is my dialogflow agent with intent
output should be coming from my local code. which is
app.intent('Welcome-Intent-yes', (conv, param) => {
conv.close('Please login ');
});
i'm not getting any firebse deploy error, but i'm not getting above output from dialogflow.
But if i only use index.js file for my function, then it works and it gives an output from dialogflow
but my requirment is to call another file with my functions inside the index.js file, like what i have done on the above code.
Related
The app, I am building with nodeJS expressJS is for connecting to a sqlserver database and retrieving data. Am trying to make the code as modular and
reusable as posssible. So different files for routing and controller. The error I am now facing is-
throw new TypeError('Router.use() requires a middleware function but got a ' + gettype(fn))
^
TypeError: Router.use() requires a middleware function but got a Object
For ease of understanding of the imports, my project structure is as such:
controller
|-- controller.js
db
|-- db.js
query
|-- queries.json
routes
|-- route.js
package.json
server.js
My main server.js file is
const express = require('express')
const bodyParser = require('body-parser')
const cors = require('cors')
const fs = require('fs')
const path = require('path')
const morgan = require('morgan')
const router=require('./routes/route');
const app = express()
app.use(cors());
app.use(bodyParser.urlencoded({ extended: false }));
// parse application/json
app.use(bodyParser.json());
app.use(morgan('dev'));
const port = 3200
app.listen(process.env.PORT || port , (err) => {
if(err)
{
console.log('Unable to start the server!');
}
else
console.log('NodeExpress Data API started running on : ' + port);
})
the controller file is
const express=require('express')
const { sql, poolPromise } = require('../db/db')
const fs = require('fs');
class MainController
{
async getAllData(req, resp)
{
try
{
const pool = await poolPromise
const result = await pool.request()
.query("select * from players");
resp.json(result.recordset)
}
catch (error)
{
resp.status(500)
resp.send(error.message)
}
}
}
const controller=new MainController();
module.exports=controller;
and the route file is
const express = require('express');
const controller = require('../controller/controller')
const router = express.Router();
router.get('/getAllData', controller.getAllData);
So when I insert this line
app.use('api/', router) in the server.js to wire all the modules together and make calls to api endpoint to get all data, I am getting that error mentioned.
What is it about, can anyone explain me in simple terms? Is the error being thrown from the controller file, since I am initializing a new instance of the controller type? Which line from which file is throwing this error? What is the code correction needed to remove this error?
under route.js change to router.get('/getAllData', controller.getAllData()); you have passed controller.getAllData as a handler function instead of controller.getAllData() as per the type of method you have used in class. hope this solves the error.
Try out one of these:
1- if your are using express and doing
const router = express.Router();
make sure to
module.exports = router ;
at the end of your page
2- If your are using express above 2.x, you have to declare app.router like below code. Please try to replace your code
app.use('/', routes);
with
app.use(app.router);
routes.initialize(app);
I currently have an Express server I'm using for a mobile app which is structured as follows (server.js):
const PostRouter = require('./api/production/Post');
const UserRouter = require('./api/production/User');
...
app.use('/posts', PostRouter)
app.use('/users', UserRouter)
and then in api/production/Post I have:
router.get('/fetch', (req, res) => {
...
}
router.get('/delete', (req, res) => {
...
}
etc..
However, I would really like to rebuild the server to match the structure of my corresponding NextJS app and its API structure, which would be something like:
/api/posts/
add-post/
index.js
fetch-all/
index.js
edit-post/
index.js
Where each index.js file contains just one endpoint/query instead of the current structure where each file has multiple queries with the router.get thing.
It looks like this is possible by creating a Router for each endpoint with something like:
const PostFetchAllRouter = require('./api/posts/fetch-all');
const PostEditPostRouter = require('./api/posts/edit-post');
...
app.use('posts/fetch-all', PostFetchAllRouter)
app.use('posts/edit-post', PostEditPostRouter)
What would be the best way to do this, please? Is there an easier way to do this without all the boilerplate in the server.js file? I'm very new to Express - please excuse if it's a naive question
You could move the "boilerplate" code to the different router files and build a router chain. But you have to write a little bit more.
server.js
|-api/
|--posts/
|---PostsRouter.js
|---fetchAll.js
|--users/
|---UserRouter.js
fetchAll.js
const express = require("express");
const FetchAll = express.Router();
FetchAll.get("/fetch", (req, res) => { res.send("/posts/fetch") });
module.exports = FetchAll;
PostsRouter.js
const express = require("express");
const FetchAll = require("./fetchAll");
const PostsRouter = express.Router();
PostsRouter.use(FetchAll);
module.exports = PostsRouter;
server.js
const express = require('express');
const PostsRouter = require("./api/posts/PostsRouter");
let app = express();
app.use("/posts", PostsRouter);
app.listen(80, () => {});
If you build it like that you would plug the small routers into the next bigger one and then use them in the server.js.
GET localhost/posts/fetch HTTP/1.1
// returns in my example the string "/posts/fetch"
Is that what you were looking for?
I have set up multiple webhook endpoints that follow the similar structure in Node.js: 1) stringify the JSON request and 2) do something about that stringified request in R.
This consequently leads to a lot of duplicate code, and I attempt to stay DRY by creating a function in which I specify the arguments that actually do change. Here's an example.
First, the top portion of the script:
require("dotenv").config();
const express = require("express");
const app = express();
const port = 3000;
app.use(express.json());
Then, the part I would like to rewrite into a master function (WH) in which everything capitalized below between < and > becomes the argument.
app.post(<ENDPOINT>, foobar);
function foobar(req, res) {
var spawn = require("child_process").spawn;
let body = JSON.stringify(req.body);
var R_shell = spawn("/usr/local/bin/Rscript", [<PATH_TO_SCRIPT>, body]);
res.end("Processing completed");
}
app.get(<ENDPOINT>, (req, res) => res.send(`<html><body><h1>All working!</h1></body></html>
`));
Hence, with two endpoints, I'd end up with:
require("dotenv").config();
const express = require("express");
const app = express();
const port = 3000;
app.use(express.json());
WH(endpoint="foo", script_path="baz")
WH(endpoint="lorem", script_path="dolor")
P.S. Sorry if this is poorly formulated question from a Node.js standpoint—it's my first time developing with Node.js.
If I understood your question correctly, what you can do is something like this:
Firstly, you need to create a function that returns a router with the specified routes (You could create this function in a different file to make the code cleaner).
const {Router} = require('express')
function WH(endpoint, scriptPath) {
const router = Router()
function fn(req, res) {
var spawn = require("child_process").spawn;
let body = JSON.stringify(req.body);
var R_shell = spawn("/usr/local/bin/Rscript", [scriptPath, body]);
res.end("Processing completed");
}
router.post(endpoint, fn);
router.get(endpoint, (req, res) => res.send(`<html><body><h1>All working!</h1></body></html>`));
return router
}
And finally you should use it like this:
require("dotenv").config();
const express = require("express");
const app = express();
const port = 3000;
app.use(express.json());
app.use(WH("/foo", "./baz"))
app.use(WH("/lorem", "./dolor"))
I have 2 separate swagger API documentations which I want to run via swagger-ui-express NPM package, and my express server is starting fine on port 5000, but when I am trying to access any of the URL always getting the 404 error, Here is my app.js file and URL's for your reference:
Route 1: http://localhost:5000/edi
Route 2: http://localhost:5000/ecom
const express = require('express');
const router = require('express').Router();
const swaggerUi = require('swagger-ui-express');
const ediSwaggerDocument = require('./edi-openapi.json');
const ecomSwaggerDocument = require('./ecom-openapi.json');
const SWAGGER_APP_PORT = process.env.SWAGGER_APP_PORT || 5000;
const app = express();
// Route Middleware to be called before serving Any Route
router.use('/', swaggerUi.serve);
// Route - EDI RESTful API Documentaion
router.get('/edi', swaggerUi.setup(ediSwaggerDocument));
// Route - eCommerce RESTful API Documentaion
router.get('/ecom', swaggerUi.setup(ecomSwaggerDocument));
app.listen(SWAGGER_APP_PORT, () => console.log(`RESTful API Up and Running on Port ${SWAGGER_APP_PORT}`));
Try the following configurations to hook swaggerUi with express-app
app.use("/edi", swaggerUi.serve, (...args) => swaggerUi.setup(ediSwaggerDocument)(...args));
app.use("/ecom", swaggerUi.serve, (...args) => swaggerUi.setup(ecomSwaggerDocument)(...args));
I haven't dig enough into the swagger-ui-express but i think the problem comes from the function generateHTML (called in swaggerUi.setup). A global module variable (swaggerInit) is updated when called.
So the last call to generateHTML has side effects on every routes that use swaggerUi.setup middleware.
A quick fix is to generate HTML each time the route is called. According to the code snippet you provide, it should looks like :
let swaggerDocEdi = require('./edi-openapi.json');
let swaggerDocEcom= require('./ecom-openapi.json');
let router = express.Router();
router.use('/api/edi', swagger.serve, (req, res) => {
let html = swagger.generateHTML(swaggerDocEdi);
res.send(html);
});
router.use('/api/ecom', swagger.serve, (req, res) => {
let html = swagger.generateHTML(swaggerDocEcom);
res.send(html);
});
Note that the global variable is still updated.
router.use('/jobs/api/:id',swaggerUi.serve,(req,res)=>{
console.log("here")
let a = req.params.id
if(a==='all'){ res.status(200).send(swaggerUi.generateHTML(swaggerDocument))}
if(a==='google'){res.status(200).send(swaggerUi.generateHTML(GoogleAds)) }
});
I was also looking for a solution for this issue, and found a better solution recommended by Swagger UI Express. check the link below
https://github.com/scottie1984/swagger-ui-express#two-swagger-documents
const express = require('express');
const app = express();
const swaggerUi = require('swagger-ui-express');
const swaggerDocumentOne = require('./swagger-one.json');
const swaggerDocumentTwo = require('./swagger-two.json');
var options = {}
app.use('/api-docs-one', swaggerUi.serveFiles(swaggerDocumentOne, options), swaggerUi.setup(swaggerDocumentOne));
app.use('/api-docs-two', swaggerUi.serveFiles(swaggerDocumentTwo, options), swaggerUi.setup(swaggerDocumentTwo));
Hope this will help others as well.
It looks like the Router is being used incorrectly. For this simple use case I would recommend adding your routes directly to the app instance. See:
const express = require('express');
// xxxx const router = require('express').Router();
const swaggerUi = require('swagger-ui-express');
const ediSwaggerDocument = require('./edi-openapi.json');
const ecomSwaggerDocument = require('./ecom-openapi.json');
const SWAGGER_APP_PORT = process.env.SWAGGER_APP_PORT || 5000;
const app = express();
// Route Middleware to be called before serving Any Route
app.use('/', swaggerUi.serve); // replaced router with app
// Route - EDI RESTful API Documentaion
// REPLACED "router" with "app"
app.get('/edi', swaggerUi.setup(ediSwaggerDocument));
// Route - eCommerce RESTful API Documentaion
// REPLACED "router" with "app"
app.get('/ecom', swaggerUi.setup(ecomSwaggerDocument));
app.listen(SWAGGER_APP_PORT, () => console.log(`RESTful API Up and Running on Port ${SWAGGER_APP_PORT}`));
Now, you could use the Router by adding it to the app instance with app.use(). See:
// Route - EDI
router.get('/edi', swaggerUi.setup(ediSwaggerDocument));
// Route - eCommerce
router.get('/ecom', swaggerUi.setup(ecomSwaggerDocument));
// Adding it to App instance
app.use('/swagger', router)
// End Point => localhost:5000/swagger/edi
Hope this helps!!
I have an Express app that I am trying to integrate with Google Assistant.
I've installed https://www.npmjs.com/package/actions-on-google and have followed https://codelabs.developers.google.com/codelabs/actions-1/#0 which deploys functions to Firebase - however I would like to run them from a self-hosted Express server.
In my app.js I have set up as follows:
const {
dialogflow,
Image,
} = require('actions-on-google')
// Create an app instance
const gapp = dialogflow();
});
However I am unsure how to create the route that I add in Dialogflow console as the webhook - do I use the format below?
app.post('/webhook', function(req, res){
gapp.intent('favorite color', (conv, {color}) => {
const luckyNumber = color.length;
// Respond with the user's lucky number and end the conversation.
conv.close('Your lucky number is ' + luckyNumber);
});
});
If so do all of my intents then go within this route?
EDIT
Updated in response to answer:
const express = require('express');
const bodyParser = require('body-parser');
const app = express();
const {
dialogflow,
Image,
} = require('actions-on-google')
// Create a google app instance
const gapp = dialogflow()
// Register handlers for Dialogflow intents
gapp.intent('Default Welcome Intent', conv => {
conv.ask('Hi, how is it going?')
conv.ask(`Here's a picture of a cat`)
conv.ask(new Image({
url: 'https://developers.google.com/web/fundamentals/accessibility/semantics-builtin/imgs/160204193356-01-cat-500.jpg',
alt: 'A cat',
}))
})
// Intent in Dialogflow called `Goodbye`
gapp.intent('Goodbye', conv => {
conv.close('See you later!')
})
gapp.intent('Default Fallback Intent', conv => {
conv.ask(`I didn't understand. Can you tell me something else?`)
})
app.post('/ga/webhook', gapp)
You can define all of your gapp intents at the start of your Express server, then you can pass in your gapp object into the webhook that you define:
const express = require('express')
const bodyParser = require('body-parser')
// ... gapp code here
const expressApp = express().use(bodyParser.json())
expressApp.post('/webhook', gapp)
expressApp.listen(3000)