Here is my server.js:
import express from "express";
import mongoose from "mongoose";
import productRouter from "./routers/productRouter.js";
import dotenv from "dotenv";
dotenv.config();
const app = express();
app.use(express.json());
let prof = process.env.PROF;
mongoose.connect(
`${prof}`
);
// Add headers before the routes are defined
app.use(function (req, res, next) {
// Website you wish to allow to connect
res.setHeader("Access-Control-Allow-Origin", "*");
// Request methods you wish to allow
res.setHeader(
"Access-Control-Allow-Methods",
"GET, POST, OPTIONS, PUT, PATCH, DELETE"
);
res.header("Access-Control-Allow-Headers", "Content-Type");
// Request headers you wish to allow
// res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,content-type');
// Set to true if you need the website to include cookies in the requests sent
// to the API (e.g. in case you use sessions)
res.setHeader("Access-Control-Allow-Credentials", true);
// Pass to next layer of middleware
next();
});
/*
app.get("/api/products", (req, res) => {
res.send(data);
});*/
app.use("/api/products", productRouter);
app.get("/", (req, res) => {
res.send("Server is ready");
});
const port = process.env.PORT || 5000;
app.listen(port);
Going inside productRouter.js ...
import express from "express";
import mongoose from "mongoose";
import data from "../data.js";
import Product from "../models/productModel.js";
import { payment } from "./paymentController.js";
const productRouter = express.Router();
productRouter.use("/pay", async (req, res, next) => {
// dont store cart in db, store it in local storage. On checkout get Id of all items in cart. Then find their prices from the db and charge correctly.
console.log("middleware ran");
console.log(req.body);
const productIdsAndAmounts = req.body.basketItems.items.map((item) => {
return { id: item.id, amount: item.amount };
});
// this works faster (apparently)
/*
const objIds = productIds.map((id) => mongoose.Types.ObjectId(id));
const orderedItems = await Product.find({
_id: { $in: objIds },
});
*/
// this sends more query requests to db
const orderedItems = await Promise.all(
productIdsAndAmounts.map((productId) => {
return Product.findById(productId.id);
})
);
let i = -1;
let productIdsPricesAmounts = [];
orderedItems.forEach((item) => {
i = i + 1;
productIdsPricesAmounts.push({
id: item.id,
price: item.price,
amount: productIdsAndAmounts[i].amount,
});
});
console.log(productIdsPricesAmounts);
const prices = productIdsPricesAmounts.map((item) => {
return item.price * item.amount;
});
const reducer = (prevValue, currValue) => prevValue + currValue;
const totalTotalPrice = prices.reduce(reducer);
console.log(totalTotalPrice);
req.totalPrice = totalTotalPrice;
//console.log(orderedItems);
//console.log(productIdsAndAmounts);
// console.log(req.body.user); // adres
next();
});
productRouter.get("/", async (req, res) => {
const products = await Product.find({});
res.send(products);
});
productRouter.post("/pay", payment);
export default productRouter;
Now to the paymentController.js:
export const paymentController = async (req, res, next) => {
console.log(req.body.basketItems)
/* returns contents of the body like expected, i can do whatever i want with it*/
}
The behaviour, i can get is:
Client sends request to "api/products/pay", i have access to req.body in paymentController.
The behaviour, i want is:
Client sends request to "api/products/pay", the request first goes through a middleware where i do some calculations on it, then i forward the new variable to my paymentController. The problem is req.body is {} in middleware productRouter.use(), but available in paymentController
What am I doing wrong ? I'm new to express and i don't exactly know what I'm doing yes. I want to have access to req.body inside productRouter. I'm guessing i set up the middleware wrong or something like that. But I can't see what i did wrong.
Can You Use
Router For Example :
user.ts
import express from "express";
let UserRoute = express.Router()
UserRoute.get('/',function (req,res) {
res.json('Hello World')
})
export { UserRoute }
App.ts
import express from "express";
import cors from "cors";
import { UserRoute } from "./routes/v1/user"
const http = require('http');
const app = express();
const server = http.createServer(app);
const PORT : string|number = process.env.PORT || 5000;
app.use(cors());
app.use(express.json());
app.use('/',UserRoute)
//Run Server And Listen To Port
server.listen(PORT,()=>{
console.log("Server UP")
})
Guess this is your main route where you want to add middleware function right
Create a middle were function with name "abc" export from there as name "abc"
Now, here in main route you can use that function as a middleware
productRouter.post("/pay",abc, payment);
here abc is your middleware function
Related
I have some routes on my API. And have a middleware. Its creating bearer token and checking it. But i want some of my routes dont enter to that middleware so i can access without token. How can i make it ? My middleware :
app.use(async (req, res, next) => {
if (
req.path === "/api/v1/collection/byhome" || // I dont want that part.
req.path === "/api/v1/user/login" // Its working but its not looks like best solution.
) {
next();
} else {
const bearerHeader = req.header("authorization");
if (typeof bearerHeader !== "undefined") {
const bearer = bearerHeader.split(" ");
const bearerToken = bearer[1];
req.token = bearerToken;
jwt.verify(req.token, process.env.SECRETKEY, async (err, authData) => {
if (err) {
res.sendStatus(401);
} else {
next();
}
});
} else {
res.statusCode = 400;
const Response = {
message: "Invalid Token",
StatusCode: res.statusCode,
};
res.json(Response);
}
}
});
My Route :
app.get(
`/api/${version}/article/bycollection/:id`,
ArticleRoute.getbycollection
);
your way of doing it is correct you can make your code more readable by making an array of all the middleware you want to be out of scope of your middleware
const whiteListEndpoints = ["/api/v1/this", "/api/v1/this1", "/api/v1/this2"]
then
// your middleware
app.use((req, res,next) => {
//if the path was in the whitelist just call next function
if(whiteListEndpoints.includes(req.url)) return next()
// let the middlware do it's job
})
or you can change your express use order
const firstRoute = app.use("/no_middleware", router);
app.use((req, res, next) => {}) // your middleware
const secondRoute = app.use("/with_middleware", router);
here the first router won't use the middleware since it has not yet been called.
You can use Express.Router to achieve the desired result. With express router you can differentiate between routes and have different middlewares for each router.
Follow the steps given below:
Create a auth middleware middlewares/private.authenticate.js
function auth(req, res, next) {
// do auth stuff...
next();
}
Create a file routes/private/index.js
// private route handler
import { Router } from "express";
import auth from "./middlewares/private.authenticate.js";
const router = Router();
router.use(auth); // use auth middleware
router.route("/")
.get()
.put()
export default router;
Create a file routes/public/index.js
import { Router } from "express";
const router = Router();
router.route("/")
.get()
.put()
export default router;
Your express app file
import express from "express";
const app = express();
import PublicRoutes from "./routes/public";
import PrivateRoutes from "./routes/private";
// public routes path
app.use("/api/public", PublicRoutes);
// private routes path
app.use("/api/private", PrivateRoutes);
You can create a route express.Router() and set this to a path, this router have all auth, then create a second express.Router() and this without auth.
var router = express.Router();
// your code for API auth...
router.get('/api/v1/collection/byhome',myMiddleware, (req, res, next) => {
res.send('Hey There');
})
app.use('/api', router);
var routerGuest = express.Router();
//
routerGuest.get('/', (req, res, next) => {
res.send('Hey There');
})
app.use('/guest', routerGuest)
for authentication, I recomend to make a separate middleware and then pass it to our route
function myMiddleware(req, res, next){
const bearerHeader = req.header("authorization");
if (typeof bearerHeader !== "undefined") {
const bearer = bearerHeader.split(" ");
const bearerToken = bearer[1];
req.token = bearerToken;
jwt.verify(req.token, process.env.SECRETKEY, async (err, authData) => {
if (err) {
res.sendStatus(401);
} else {
next();
}
});
} else {
res.statusCode = 400;
const Response = {
message: "Invalid Token",
StatusCode: res.statusCode,
};
res.json(Response);
}
}
}
I think with this you may have some idea to do it :)
I have to access a state from server. I want to change the twitterName with a mutation after figure out from this. I set a getter but when I try to import store to js file it sends error. How can I import a state?
server/index.js
const express = require('express')
const bodyParser = require('body-parser')
const cors = require('cors')
const path = require('path')
const app = express()
app.use(bodyParser.json())
app.use(cors())
const tweets = require('./routes/api/tweets')
const twitterName = require('./routes/api/name')
app.use('/api/tweets', tweets)
app.use('/name/', twitterName)
if (process.env.NODE_ENV === 'production') {
app.use(express.static(__dirname + '/public/'))
app.get(/.*/, (req, res) => res.sendFile(__dirname + '/public/index.html'))
}
const port = process.env.PORT || 8081
app.listen(port, () => console.log(`Server started on port ${port}`))
server/name.js
const express = require('express')
const router = express.Router()
router.get('/:twitterName', (req, res) => {
const name = req.params.twitterName
res.status(200).send(name)
})
module.exports = router
store.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
twitterName: 'name1234'
},
getters: {
twitterName: (state) => state.twitterName
}
actions: {
updateId({ commit }, id) {
commit('setId', id)
},
async getTweetData({ state }) {
const res = await axios.get('http://localhost:8081/name/' + state.twitterName)
// do what you want with the data
}
},
})
You can’t use the store from the client in your express server from the simple reason that all the data used in client side of your application, including vuex store is saved in the browser, and you don’t have access to it in the server. This is not the correct way to achieve your goal.
If you want to use data from the client you need to send it to your server, so you could use it there. So if you need the twitterName specifically you can do something like this:
router.get('/tweets/:twitterName', (req, res) => {
// const name = 'name123'
const name = req.params.twitterName
T.get(
'search/tweets',
{ from: name, count: 5 },
function (err, data, response) {
if (err) {
return res.status(400).json('Oops! Something went wrong.')
}
data.twitterName = '<new-name>'
res.status(200).send(data)
}
)
})
And from the vuejs store:
actions: {
async getTweetData({ state, commit }) {
const res = await axios.get('<your-server-ip>/' + state.twitterName)
commit('setTwitterName', res.data.twitterName)
}
},
mutations: {
setTwitterName(state, newTwitterName) {
state.twitterName = newTwitterName
}
}
Been stuck on this over an hour or two now >.<
I am unable to access the request body for the user api. I can get the response 'hi' back using res.send (see screenshot) but not with any req.body values. Email is coming back undefined :/
Any ideas where I am going wrong?
Content type is set to json on the postman headers.
Controller:
import asyncHandler from 'express-async-handler'
const authUser = asyncHandler(async (req, res) => {
const { email, password } = req.body
res.send('hi' + email)
})
export {authUser}
Route:
import express from 'express'
const router = express.Router()
import { authUser } from '../controllers/userController.js'
router.post('/login', authUser)
export default router
hiundefined ^
Server.js
import express from 'express'
import dotenv from 'dotenv'
import connectDB from './config/db.js'
import productRoutes from './routes/productRoutes.js'
import userRoutes from './routes/userRoutes.js'
import colours from 'colours'
import { notFound, errorHandler} from './middleware/errorMiddleware.js'
dotenv.config()
connectDB()
const app = express()
app.use(express.json())
app.get('/', (req, res) => {
res.send('API is running...')
})
app.use('/api/products/', productRoutes)
app.use('/api/users/', userRoutes)
app.use(notFound)
app.use(errorHandler)
const PORT = process.env.PORT || 5000
app.listen(
PORT,
console.log(`Server running in ${process.env.NODE_ENV} mode on port ${PORT}`.yellow.bold)
)
Headers:
use this middleware because if you are using Express 4.16+ you can app.use(express.json())
const bodyParser = require("body-parser");
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyparser.json());
and update your header request accept Content-Length : <calculated when request is sent>
``
I believe you need to pass the request req through to your authUser function
router.post('/login', (req, res) => {
authUser(req, res)
});
I am creating a project in DialogFlow and NodeJS where I want to call my fulfillments with a webhook.
In my NodeJS server, I have multiple routes for different functions/intents. For example, /getWeather calls a weather API to return a response about the weather in a specific city. Or /getMovie calls an API to return information about a movie.
DialogFlow only allows for one webhook API, so my question is, how can I call a generic API "/" where it can handle all the different routes and call the correct route when it needs to?
I can use the inline editor on DialogFlow to call each API with the correct route; however, I want to use a single webhook rather than using the firebase functions to call the correct intents.
I can't seem to find example of this online where multiple routes are handled with a generic route.
Image of my Code Stack
index.js:
const http = require('http');
const app = require('./app');
const port = process.env.PORT || 3000;
const server = http.createServer(app);
server.listen(port);
server.post
app.js
const express = require('express');
const app = express();
const morgan = require('morgan');
const bodyParser = require('body-parser');
const mongoose= require('mongoose');
const issuesRoutes = require('./API/Routes/issues');
const movieRoute = require('./API/Routes/getmovie');
const resolvedtaskroute = require('./API/Routes/resolvedtask');
const newtaskRoute = require('./API/Routes/newtask');
mongoose.connect('link', {
useNewUrlParser: true,
useUnifiedTopology: true
})
.then(() => console.log('MongoDB connected...'))
.catch(err => console.log(err));
app.use(morgan('dev'));
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
app.use((req, res, next) => {
res.header('Acces-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Headers', '*');
if (req.method === 'OPTIONS'){
res.header('Access-Control-Allow-Methods', 'PUT, POST, PATCH, DELETE, GET');
return res.status(200).json({});
}
next();
});
//routes to handle requests
app.use('/issues', issuesRoutes);
app.use('/newtask', newtaskRoute);
app.use('/resolvedtask', resolvedtaskroute);
app.use('/getmovie', movieRoute);
//error handling
app.use((req, res, next) => {
const error = new Error('Not Found');
error.status = 404;
next(error);
})
app.use((error, req, res, next) => {
res.status(error.status || 500);
res.json({
error: {
message: error.message
}
})
})
module.exports = app;
Example of one of my routes: getMovie.js
const express = require('express');
const router = express.Router();
const http = require('http');
router.post('/', (req, res, next) => {
const movieToSearch = req.body.queryResult.parameters.movie;
const API_KEY = 'XXXXX';
const reqUrl = `http://www.omdbapi.com/?t=${movieToSearch}&apikey=${API_KEY}`
http.get(
reqUrl,
responseFromAPI => {
let completeResponse = ''
responseFromAPI.on('data', chunk => {
completeResponse += chunk
})
responseFromAPI.on('end', () => {
const movie = JSON.parse(completeResponse)
let dataToSend = movieToSearch
dataToSend = `${movie.Title} was released in the year ${movie.Year}. It is directed by ${
movie.Director
} and stars ${movie.Actors}.
}`
return res.json({
fulfillmentText: dataToSend,
source: 'getmovie'
})
})
},
error => {
return res.json({
fulfillmentText: 'Could not get results at this time',
source: 'getmovie'
})
}
)
})
module.exports = router;
It is very clear that Dialogflow allows one webhook POST url where every call for intents are made. IF you want to use different API services inside then You should define a webhook and inside the webhook just call the functions which are related to intents using intentMAP. On each function call the external API and return the response back to dialogflow. I will describe a bit more about it using dialogflow-fulfillment.
first thing you need is a webhook POST route for handling dialogflow requests and responses and inside it you need to map intents to its specific function as like:
const { WebhookClient } = require("dialogflow-fulfillment");
const movieService= require("your function for movie API");
router.post("/", async (req, res, next) => {
const agent = new WebhookClient({ request: req, response: res });
const movie = new movieService(agent);
let intentMap = new Map();
intentMap.set("Movie Intent", () => {
//make an api call inside this function
return movie.getinfo();
});
if (agent.intent) {
agent.handleRequest(intentMap);
}
});
Now create another file for external API calls which will be like
async getMovie(){
// get all required paramters from dialogflow here and call APIS and return back response using
agent.add("The info about movie is");
}
I just starting to use node.js to build a RESTFul api. I'm now trying to insert data by post with json in body.
But when I try to get req.body always got undifined.
So I check at here. Saw some people said that the express configuration should before the route.
After I modified my code. I can't even get home page.
Can anyone help me solve this problem?
express.js before
/* express.js */
import bodyParser from 'body-parser';
import express from 'express';
import cors from 'cors';
import morgan from 'morgan';
import config from './config';
import index from '../server/routes/index.route';
const app = express();
/* GET home page. */
app.get('/', (req, res) => {
res.send(`server started on port.. http://127.0.0.1:${config.port} (${config.env})`);
});
app.use('/api', index);
// parse body params and attache them to req.body
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(cors);
// Http request logger
app.use(morgan('dev'));
export default app;
POST RESULT
{
"code": "ER_PARSE_ERROR",
"errno": 1064,
"sqlMessage": "You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '?' at line 1",
"sqlState": "42000",
"index": 0,
"sql": "INSERT INTO Article SET ?"
}
express.js after
/* express.js */
/* ... */
const app = express();
// parse body params and attache them to req.body
app.use(bodyParser.json);
app.use(bodyParser.urlencoded({ extended: true }));
app.use(cors);
// Http request logger
app.use(morgan('dev'));
/* GET home page. */
app.get('/', (req, res) => {
res.send(`server started on port.. http://127.0.0.1:${config.port} (${config.env})`);
});
app.use('/api', index);
export default app;
index.js
import config from './config/config';
import app from './config/express';
if (!module.parent) {
// listen on port config.port
app.listen(config.port, () => {
console.log(`index.js >>> server started on port http://127.0.0.1:${config.port} (${config.env})`);
});
}
export default app;
index.route.js
import express from 'express';
import mysql from 'mysql';
import article from './article.route';
import config from './../../config/config';
const router = express.Router();
/* GET localhost:[port]/api page. */
router.get('/', (req, res) => {
res.send(`此路徑是: localhost:${config.port}/api`);
});
/* mysql連線測試 */
router.get('/sqlTest', (req, res) => {
const connectionPool = mysql.createPool({
connectionLimit: 10,
host: config.mysqlHost,
user: config.mysqlUserName,
password: config.mysqlPass,
database: config.mysqlDatabase
});
connectionPool.getConnection((err, connection) => {
if (err) {
res.send(err);
console.log('連線失敗!');
} else {
res.send('連線成功!');
console.log(connection);
}
});
});
// article router
router.use('/article', article);
export default router;
article.route.js
const router = express.Router();
router.route('/').post(articleCtrl.articlePost);
article.controller.js
const articlePost = (req, res) => {
const insertValues = req.body;
console.log('insertValues ', insertValues);
articleModule.createArticle(insertValues).then((result) => {
res.send(result);
}).catch((err) => { return res.send(err); });
};
you need to call bodyParser.json and cors as a function; app.use(bodyParser.json());, app.cors()