Express js render error this.engine is not a function - express

I'm trying to develop a small API using express. Just want to have 2 views, which, in my case, means 2 html files. One accesing as default with "/" and the other with "/lessons", so we got 2 get controls plus another one which handles every other get input.
*Both files are in the "views" folder and their extension is: *.html
I have no problem accessing the "app.get("/lessons", function..." in fact I know I can acces to that because a simple "console.log(..)" command. The problem is that I got the next error when trying to render:
[TypeError: this.engine is not a function].
Could you help me? I can't understand where is the problem or what I'm doing wrong. I believe it's in the rendering function and has something to do with its configuration and the lessons.html file because index.html has no problem using the same approach.
var express = require('express');
var app = express();
var mod = require('./module');
app.use(express.static('public'));
app.use(express.static('views'));
var port = process.env.PORT || 8080;
app.listen(port, function() {
console.log('Node.js listening on port ' + port);
});
app.get("/", function(req, res) {
console.log("Passed through /");
res.render('index.html');
});
app.get("/lessons", function(req, res) {
console.log("passed through lessons");
res.render('lessons.html', function(err, html) {
if(err) {
console.log(err);
}
res.send(html);
});
//I have tried to to use just: res.render('lessons.html');
});
app.get("*", function(req, res) {
var usageReq = false;
var urlPassed = req.url;
urlPassed = urlPassed.substring(1, urlPassed.length); //remove first "/"
var expected = mod.seeIfExpected(urlPassed); //returns url(if url) or num(if number) or na(if it doesn't match any)
mod.processInfo(expected, urlPassed, function(answer) {
if (answer.found == false && answer.jsonRes == true && answer.info != "inserted") {
res.json({
"error": answer.info
});
} else {
if (answer.jsonRes == true) {
res.json({
"long_url": answer.url,
"short_url": answer.id
});
} else { // go to url
var newUrl = "https://" + answer.url;
res.redirect(newUrl);
}
}
});
});

Related

Serving/downloading PDF file from Deno [duplicate]

Deno seems targeting text files, but I also need to serve image files for the website.
You can use send()
The function send() is designed to serve static content as part of a
middleware function. In the most straight forward usage, a root is
provided and requests provided to the function are fulfilled with
files from the local file system relative to the root from the
requested path.
const app = new Application();
app.use(async (context) => {
await send(context, context.request.url.pathname, {
root: `${Deno.cwd()}/static`
});
});
await app.listen({ port: 8000 });
With the following directory structure:
static/
image.jpg
server.js
You can access the image by going to http://localhost:8000/image.jpg
Basically, you just need to set the correct headers for your image type, and supply the image data as a Unit8Array:
In your middleware:
app.use(async (ctx, next) => {
// ...
const imageBuf = await Deno.readFile(pngFilePath);
ctx.response.body = imageBuf;
ctx.response.headers.set('Content-Type', 'image/png');
});
Here's a complete working example, which will download a sample image (the digitized version of the hand-drawn deno logo) and serve it at http://localhost:8000/image, and display "Hello world" at all other addresses. The run options are in the comment on the first line:
server.ts
// deno run --allow-net=localhost:8000,deno.land --allow-read=deno_logo.png --allow-write=deno_logo.png server.ts
import {Application} from 'https://deno.land/x/oak#v5.3.1/mod.ts';
import {exists} from 'https://deno.land/std#0.59.0/fs/exists.ts';
// server listen options
const listenOptions = {
hostname: 'localhost',
port: 8000,
};
// sample image
const imageFilePath = './deno_logo.png';
const imageSource = 'https://deno.land/images/deno_logo.png';
const ensureLocalFile = async (localPath: string, url: string): Promise<void> => {
const fileExists = await exists(localPath);
if (fileExists) return;
console.log(`Downloading ${url} to ${localPath}`);
const response = await fetch(url);
if (!response.ok) throw new Error('Response not OK');
const r = response.body?.getReader;
const buf = new Uint8Array(await response.arrayBuffer());
await Deno.writeFile(imageFilePath, buf);
console.log('File saved');
};
await ensureLocalFile(imageFilePath, imageSource);
const app = new Application();
app.use(async (ctx, next) => {
// only match /image
if (ctx.request.url.pathname !== '/image') {
await next(); // pass control to next middleware
return;
}
const imageBuf = await Deno.readFile(imageFilePath);
ctx.response.body = imageBuf;
ctx.response.headers.set('Content-Type', 'image/png');
});
// default middleware
app.use((ctx) => {
ctx.response.body = "Hello world";
});
// log info about server
app.addEventListener('listen', ev => {
const defaultPortHttp = 80;
const defaultPortHttps = 443;
let portString = `:${ev.port}`;
if (
(ev.secure && ev.port === defaultPortHttps)
|| (!ev.secure && ev.port === defaultPortHttp)
) portString = '';
console.log(`Listening at http${ev.secure ? 's' : ''}://${ev.hostname ?? '0.0.0.0'}${portString}`);
console.log('Use ctrl+c to stop\n');
});
await app.listen(listenOptions);
Register middleware like this:
// serve static files
app.use(async (context, next) => {
try {
await context.send({
root: `${Deno.cwd()}/wwwroot/static`,
index: "index.html",
});
} catch {
await next();
}
});

Getting "error": "Unknown authentication strategy \"jwt\""

I'm implementing an authorization feature using Express, Mongoose, Passport and JWT.
I'm able to register a user ok. I'm able to authenticate and generate a JWT, which I can parse on the JWT site, but for some reason, I'm getting an Unknown authentication strategy error message.
I have all my code blocks laid out on a Plunker instance at:
https://plnkr.co/edit/ZNjQwcZ4rMymzBXNy5nX?p=catalogue
Here is my passport.js file, which contains my strategy:
var JwtStrategy = require('passport-jwt').Strategy;
// load up the user model
var User = require('../models/user');
var config = require('../config/database'); // get db config file
module.exports = function(passport) {
var opts = {};
opts.secretOrKey = config.secret;
passport.use(new JwtStrategy(opts, function(jwt_payload, done) {
User.findOne({id: jwt_payload.id}, function(err, user) {
if (err) {
return done(err, false);
}
if (user) {
done(null, user);
} else {
done(null, false);
}
});
}));
};
Here is what my authentication.js file looks like:
var express = require('express');
var router = express.Router();
var jwt = require('jwt-simple');
var config = require('../config/database');
var User = require('../models/user');
router.route('/')
.post(function(req, res) {
User.findOne({
name: req.body.name
}, function(err, user) {
if (err)
res.send(err);
if (!user) {
res.send({success: false, msg: 'Authentication failed. User not found.'});
} else {
// check if password matches
user.comparePassword(req.body.password, function (err, isMatch) {
if (isMatch && !err) {
// if user is found and password is right create a token
var token = jwt.encode(user, config.secret);
// return the information including token as JSON
res.json({success: true, token: 'JWT ' + token});
} else {
res.send({success: false, msg: 'Authentication failed. Wrong password.'});
}
});
}
});
});
module.exports = router;
Here is the endpoint I'm calling that is generating the error:
var express = require('express');
var router = express.Router();
var jwt = require('jwt-simple');
var config = require('../config/database');
var passport = require('passport');
var User = require('../models/user');
router.route('/')
.get(passport.authenticate('jwt', { session: false}), function(req, res) {
var token = getToken(req.headers);
if (token) {
var decoded = jwt.decode(token, config.secret);
User.findOne({
name: decoded.name
}, function(err, user) {
if (err) throw err;
if (!user) {
return res.status(403).send({success: false, msg: 'Authentication failed. User not found.'});
} else {
res.json({success: true, msg: 'Welcome in the member area ' + user.name + '!'});
}
});
} else {
return res.status(403).send({success: false, msg: 'No token provided.'});
}
});
getToken = function (headers) {
if (headers && headers.authorization) {
var parted = headers.authorization.split(' ');
if (parted.length === 2) {
return parted[1];
} else {
return null;
}
} else {
return null;
}
};
module.exports = router;
You forgot to include your own passport.js module in the application. This leads nodejs to not find the definition of JWTStrategy which is ultimately causing the error that you see.
In your endpoint file, just include the local passport.js file:
var express = require('express');
var router = express.Router();
var jwt = require('jwt-simple');
var config = require('../config/database');
var passport = require('passport');
require('./passport')(passport) // as strategy in ./passport.js needs passport object
var User = require('../models/user');
router.route('/')
.get(passport.authenticate('jwt', { session: false}), function(req, res) {
var token = getToken(req.headers);
...
if you look at your passport configuration file (passport.js) you will see
module.exports = function (passport) {
//bla bla bla
}
as you see it needs passport instance
now how to pass this instance to your passport.js file
simply
var passport = require('passport');// create a passport instance
var myPassportService = require('../config/passport')(passport);// pass it into passport.js file
hope this helps you
Just on the off chance that someone is having the same issue but it isn't resolved by the top answer.
My issue ended up being accidently moving node modules into another directory and then of course running npm install to fix module import errors. I ended up with two node_modules directory and although the server started fine, passport errored when it was called.
I eventually found the blunder and removed the second node_modules directory and the Unknown authentication strategy “jwt” was no resolved.

Express, webpack-dev-sever doesn't find React index

i'm very new of Express and server side in general, for my small react messaging app i'm using Express for the backend(a json file) and webpack dev server for frontend.
If i start just the Webpack server, the app show correctly, probelems come when i try to make the two works together and i think the problem is the proxy configuration of webpack-dev-server.
Here is my express server, json-api-server.js:
var express = require('express');
var serveStatic = require('serve-static');
var fs = require('fs');
var path = require('path');
var bodyParser = require('body-parser');
module.exports = (PORT) => {
const MESSAGES_FILE = path.join(__dirname, 'src/app/data/messages.json');
const app = express();
app.use(serveStatic(__dirname + '/build'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: true}));
// Additional middleware which will set headers that we need on each request.
app.use(function(req, res, next) {
// Set permissive CORS header - this allows this server to be used only as
// an API server in conjunction with something like webpack-dev-server.
res.setHeader('Access-Control-Allow-Origin', '*');
// Disable caching so we'll always get the latest comments.
res.setHeader('Cache-Control', 'no-cache');
next();
});
app.get('/messages', function(req, res) {
fs.readFile(MESSAGES_FILE, function(err, data) {
if (err) {
console.error(err);
process.exit(1);
}
res.json(JSON.parse(data));
});
});
app.post('/messages', function(req, res) {
fs.readFile(MESSAGES_FILE, function(err, data) {
if (err) {
console.error(err);
process.exit(1);
}
var messages = JSON.parse(data);
var newMessage = {
id: Date.now(),
body: req.body.body,
date: req.body.date,
from: req.body.from,
to: req.body.to
};
messages.push(newMessage);
fs.writeFile(MESSAGES_FILE, JSON.stringify(messages, null, 4), function(err) {
if (err) {
console.error(err);
process.exit(1);
}
res.json(messages);
});
});
});
app.listen(PORT, function (err) {
if (err) {
return console.log(err);
}
console.log('Listening at' + PORT );
});
}
This is webpack-server.js:
var webpack = require('webpack');
var WebpackDevServer = require('webpack-dev-server');
var config = require('./webpack.config');
module.exports = (PORT) => {
const backendPort = PORT - 1;
const server = new WebpackDevServer(webpack(config), {
publicPath: config.output.publicPath,
hot: true,
historyApiFallback: true,
proxy: {
'*' : {
target: 'http://localhost:' + backendPort
}
}
});
server.listen(PORT, 'localhost', function (err) {
if (err) {
return console.log(err);
}
console.log('Listening at ' + PORT);
});
}
And here is server.js:
var apiServer = require('./json-api-server');
var webpackServer = require('./webpack-server');
const PORT = process.env.PORT || 4001;
const PROD = process.env.NODE_ENV === 'production';
if (PROD) {
apiServer(PORT);
} else {
apiServer(PORT - 1);
webpackServer(PORT);
}
My filetree looks like:
--- /
----- server.js
----- webpack-server.js
----- json-api-server.js
----- src/
------- app/index.js
------- app/data/
-------------- messages.json
Both server start correctly and they don't give any errors in the terminal
I can reach localhost:4000/messages
I cannot reach localhost:4001. I got: "Can't get / "
Any helps? :)
Got it!
The * symbol here means: Use "*" to proxy all paths to the specified server.
proxy: {
'*' : {
target: 'http://localhost:' + backendPort
}
}
Which brings my index to be undefined.
So i have to point the key to the place where my json(or api) lives:
proxy: {
'/messages' : {
target: 'http://localhost:' + backendPort
}
}
As reference, this is also a valid solution:
proxy: {
'/messages': 'http://localhost:' + backendPort
}

Test multiple http requests to express application using Jasmine

I have installed Jasmine CLI globally using npm install -g jasmine
I'm trying to test multiple http requests at once using test suite below, multiple calls per each requests were sent (seeing output of console.log() but nothing returned so the test was failure, please guide me is this possible to do so ? and how to do this ?
index.js
var app = require('express')();
var request = require('request');
app.get('/', function(req, res) {
console.log('GET /');
res.status(200);
res.send('Hello World');
});
app.listen(3000);
spec/multipleRequestSpec.js
var request = require('request');
var async = require('async');
describe('express application', function() {
var baseUrl = 'http://localhost:3000';
var statusCode = [0, 0];
var b = ['', ''];
beforeEach(function(done) {
async.parallel([
function() {
request.get(baseUrl, function(err, res, body) {
statusCode[0] = res.statusCode;
b[0] = body;
})
}
,
function() {
request.post(baseUrl, function(err, res, body) {
statusCode[1] = res.statusCode;
b[1] = body;
})
}
], done());
});
it('should return 200', function() {
expect(statusCode[0]).toBe(200);
});
it('should return hello world', function() {
expect(b[0]).toEqual('Hello World');
});
it('should return error 404', function() {
expect(statusCode[1]).toBe(404);
});
});
Edited
When testing only one request I place done() inside the request() it works just fine, but I quite confuse where to place done() when using async.pararell()
spec/requestSpec.js
var request = require('request');
describe('expresss application', function() {
var baseUrl = 'http://localhost:3000';
var statusCode = 0;
beforeEach(function(done) {
request.get(baseUrl, function(err, res, body) {
statusCode = res.statusCode;
done();
});
});
it('should return 200', function() {
expect(statusCode).toBe(200);
});
});
In describe block you initiate variable body. And you use it in it blocks. But in request.get and in request.post you have callback function with parameter body which is in use instead of your describe body variable.
Change beforeEach to:
beforeEach(function(done) {
async.parallel([
function(callback) {
request.get(baseUrl, function(err, res, reqBody) {
statusCode[0] = res.statusCode;
body[0] = reqBody;
callback();
})
}
,
function(callback) {
request.post(baseUrl, function(err, res, reqBody) {
statusCode[1] = res.statusCode;
body[1] = reqBody;
callback();
})
}
], done);
});
I think that you should also check err param in request callbacks. Because there may be errors which fails/pass your tests.
For api endpoints tests it is more easy to use superagent or supertest instead of request.

403 error using node-formidable with expressjs

i've got a problem using node-formidable (https://github.com/felixge/node-formidable) with expressjs: connect-multipart is now deprecated (http://www.senchalabs.org/connect/multipart.html).
I'm trying to use node-formidable to directly parse my uploaded files but can't make it works.
Urlencoded forms are working well but not multipart. I'm not sure but i think that it comes from the connect-csrf:
Update: it works well when i remove the csrf middleware.
Error: Forbidden
at Object.exports.error (/srv/www/mysite.com/nodejs/myapp/node_modules/express/node_modules/connect/lib/utils.js:63:13)
at createToken (/srv/www/mysite.com/nodejs/myapp/node_modules/express/node_modules/connect/lib/middleware/csrf.js:82:55)
at Object.handle (/srv/www/mysite.com/nodejs/myapp/node_modules/express/node_modules/connect/lib/middleware/csrf.js:48:24)
at next (/srv/www/mysite.com/nodejs/myapp/node_modules/express/node_modules/connect/lib/proto.js:193:15)
at next (/srv/www/mysite.com/nodejs/myapp/node_modules/express/node_modules/connect/lib/middleware/session.js:315:9)
at /srv/www/mysite.com/nodejs/myapp/node_modules/express/node_modules/connect/lib/middleware/session.js:339:9
at /srv/www/mysite.com/nodejs/myapp/node_modules/connect-redis/lib/connect-redis.js:101:14
at try_callback (/srv/www/mysite.com/nodejs/myapp/node_modules/connect-redis/node_modules/redis/index.js:581:9)
at RedisClient.return_reply (/srv/www/mysite.com/nodejs/myapp/node_modules/connect-redis/node_modules/redis/index.js:671:13)
at ReplyParser.<anonymous> (/srv/www/mysite.com/nodejs/myapp/node_modules/connect-redis/node_modules/redis/index.js:313:14)
What can i do? Here is my code:
// Body parser
app.use(express.urlencoded());
app.use(function(req, res, next) {
if (req.is('multipart/form-data') && req.method == "POST") {
var form = new formidable.IncomingForm();
form.uploadDir = "mytmpfolder";
form.parse(req, function(err, fields, files) {
req.files = files;
});
}
next();
});
// Cookie parser
app.use(express.cookieParser());
// Session
app.use(express.session({
key: 'secure_session',
store: new redisStore,
secret: 'secret',
proxy: true,
cookie: {
secure: true,
maxAge: null
}
}));
// CSRF
app.use(express.csrf());
app.use(function(req, res, next){
res.locals.token = req.csrfToken();
next();
});
I found a way to finally make it works:
// Body parser
app.use(function(req, res, next) {
if (req.method == "POST") {
var form = new formidable.IncomingForm();
var fieldsObj = {};
var filesObj = {};
form.uploadDir = "/srv/www/mysite.com/nodejs/myapp/static/uploads";
form.on('field', function(field, value) {
fieldsObj[field] = value;
});
form.on('file', function(field, file) {
filesObj[field] = file;
});
form.on('end', function() {
req.body = fieldsObj;
req.files = filesObj;
next();
});
form.parse(req);
}
else {
next();
}
});