How to properly serve a dinamic image with Node and Express? - node.js

I'm having many problems to achive what I'm trying:
I want to request an image from this URL http://tapas.clarin.com/tapa/1990/02/22/19900222_thumb.jpg and show it in the view but I'm getting this showned in the view instead:
What's the proper way of achieving what I want ?
This is my code:
const app = require('express')();
var http = require('http').Server(app);
var rp = require('request-promise');
const fs = require('fs')
var url = 'http://tapas.clarin.com/tapa/1990/02/22/19900222_thumb.jpg'
app.get('/', (req, res) => {
rp(url)
.then(image => res.set('Content-Type', 'image/jpeg').send(image))
.catch(err => res.send(err));
})
http.listen(3000, () => {
console.log('listening on localhost:3000');
});

You're getting back a string from request-promise, not a buffer.Setting encoding: null, will get you a buffer which you can send back.
const app = require('express')();
var http = require('http').Server(app);
var rp = require('request-promise');
var options = {
url: 'http://tapas.clarin.com/tapa/1990/02/22/19900222_thumb.jpg',
encoding: null
}
app.get('/', (req, res) => {
rp(options)
.then(image => {
return res.end(image,'binary');
})
.catch(err => res.send(err));
})
http.listen(3000, () => {
console.log('listening on localhost:3000');
});

Related

My socket event don't trigger when I am emit it in Nodejs

My socket event doesn't trigger when I emit it in Nodejs, I know it because I don't see "Pizza" in my console.
This is my code:
const express = require("express");
const cors = require("cors");
const app = express();
const http = require('http');
const server = http.createServer(app);
const { Server } = require("socket.io");
const io = new Server(server, {
});
app.use((req, res, next) => {
req.io = io;
next()
})
app.use(cors());
io.on('connection', (socket) => {
socket.on("dummy_event", (data) => {
console.log(`Socket 🍕`); // I don't see this message in my console
if(!data.name) return;
})
});
app.get("/socket_test", (req, res) => {
req.io.emit("dummy_event", {name: "pizza"})
return res.json({data: 'dummy text'})
})
server.listen(4000, () => {
console.log(`Server Started on Port 4000`);
})

Accessing data from a REST API works with cURL but not fetch in node

I am trying to get data from a udemy API. I can get it with cURL in the console but not with fetch. Please can anyone look at my code and let me know what I am doing wrong?
const fetch = require("node-fetch");
const express = require("express");
const app = express();
const port = process.env.PORT || 3000;
const path = require("path");
app.use(express.static("public"));
app.use(express.static(path.resolve(__dirname, "public")));
app.get("/", (req, res) => {
res.sendFile("index.html", { root: __dirname });
});
app.get("/contact", (req, res) => {
res.sendFile("contact.html", { root: __dirname });
});
const client_id = "client_id";
const client_secret = "client_secret";
const client = Buffer.from(`${client_id}:${client_secret}`).toString("base64");
fetch("https://www.udemy.com/api-2.0/courses/", {
headers: {
Authorization: `Basic ${client}`,
},
})
.then((res) => res.json())
.then((json) => console.log(json))
.catch((err) => {
console.log(err);
});

Chai testing TypeError: Converting circular structure to JSON

I'm a new learner express.js I want to test simple post and get operations with tdd mechanism. I created the test, route, index and db files but when I try to test POST method it gives me this error.
This is my routes/task.js
const express = require('express');
const router = express.Router();
router.post("/api/task", async (req,res) => {
try {
const task = await new Task(req.body).save();
res.send(task);
} catch (error) {
res.send(error);
}
})
This is my test/task.js
let chai = require("chai");
const chaiHttp = require("chai-http");
const { send } = require("process");
let server = require("../index");
//Assertion Style
chai.should();
chai.use(chaiHttp);
describe('Tasks API', () => {
/**
* Test the POST Route
*/
describe('POST /api/task', () => {
it("It should POST a new task", () => {
const task = {task: "Wake Up"};
chai.request(server)
.post("/api/task")
.send(task)
.end((err, response) => {
response.should.have.status(201);
response.body.should.be.a('string');
response.body.should.have.property('id');
response.body.should.have.property('task');
response.body.should.have.property('task').eq("Wake Up");
response.body.length.should.be.eq(1);
done();
});
});
});
});
This is my db.js
var sqlite3 = require('sqlite3').verbose()
const DBSOURCE = "db.sqlite"
let db = new sqlite3.Database(DBSOURCE, (err) => {
if (err) {
// Cannot open database
console.error(err.message)
throw err
}else{
console.log('Connected to the SQLite database.')
db.run(`CREATE TABLE IF NOT EXISTS todo (
id INTEGER PRIMARY KEY AUTOINCREMENT,
task text
)`,
(err) => {
if (err) {
// Table already created
console.log(err);
}
});
}
});
module.exports = db
And this is my index.js
const connection = require('./db');
const express = require('express');
const app = express();
const cors = require("cors");
const port = process.env.PORT || 8080;
app.use(express.json());
app.use(cors());
app.get('/', (req, res) => {
res.send('Hello World');
});
app.post('/api/task', (req, res) => {
res.status(201).send(req);
});
app.listen(port, () => console.log(`Listening on port ${port}...`));
module.exports = app;
The thing that I try to do is building a test case to test the post method. I think I couldn't built the correct relations the files.
Currently, just by doing a POST request to /api/task, the error will appear. That is because of these lines in index.js:
app.post('/api/task', (req, res) => {
res.status(201).send(req);
});
The req parameter is circular, hence cannot be JSON-stringified.
Solution
In routes/task.js export the router:
const express = require('express');
const router = express.Router();
router.post("/api/task", async (req,res) => {
try {
const task = await new Task(req.body).save();
res.send(task);
} catch (error) {
res.send(error);
}
})
// By adding this line you can export the router
module.exports = router
In index.js, include the routes/task.js file and pass it to app.use(...), also remove the now-obsolete /api/task route:
const connection = require('./db');
const express = require('express');
const app = express();
const cors = require("cors");
const taskRoutes = require("./routes/task")
const port = process.env.PORT || 8080;
app.use(express.json());
app.use(cors());
app.get('/', (req, res) => {
res.send('Hello World');
});
app.use(taskRoutes)
app.listen(port, () => console.log(`Listening on port ${port}...`));
module.exports = app;
This way we got rid of the circular structure stringifying and the tests should now pass.

localhost infinitely loading nodejs

I am starting to learn Node.js and as the first step I am deploying my server using node.js
This is my code:
const express = require("express");
const { readFile } = require("fs/promises");
const app = express();
app.get('/', (request, response) => {
readFile('./home.html', 'utf8', (err, html) => {
if(err){
response.status(500).send("Sorry, we are out of order");
}
response.send(html);
})
})
app.listen(3000, () => console.log(`App available on http://localhost:3000`))
But the when i click that link, the localhost seems to be loading infintely.I have tried with different ports.I am using powershell for this and not a WSL.What seems to be the problem here?
Try to use node path module, and put your html file into root directory. It works like a charm.
const express = require("express");
const path = require("path");
// const { readFile } = require("fs/promises");
const app = express();
// app.get("/", (request, response) => {
// readFile("./home.html", "utf8", (err, html) => {
// if (!err) {
// response.status(500).send("Sorry, we are out of order");
// }
// response.send(html);
// });
// });
app.get("/", function (req, res) {
res.sendFile(path.join(__dirname, "/home.html"));
});
app.listen(3000, () => console.log(`App available on http://localhost:3000`));

Node.js + Express - How to log the request body and response body

I have a small api I have built using Node.js and express.
I am trying to create a logger and I need log the request body AND response body.
app.use((req, res) => {
console.log(req);
res.on("finish", () => {
console.log(res);
});
});
"express": "^4.16.3",
However, i am not able to find the body in the req or res object. Please tell me how i can get them. thanks.
For res.body try the following snippet:
const endMiddleware = (req, res, next) => {
const defaultWrite = res.write;
const defaultEnd = res.end;
const chunks = [];
res.write = (...restArgs) => {
chunks.push(new Buffer(restArgs[0]));
defaultWrite.apply(res, restArgs);
};
res.end = (...restArgs) => {
if (restArgs[0]) {
chunks.push(new Buffer(restArgs[0]));
}
const body = Buffer.concat(chunks).toString('utf8');
console.log(body);
defaultEnd.apply(res, restArgs);
};
next();
};
app.use(endMiddleware)
// test
// HTTP GET /
res.status(200).send({ isAlive: true });
You need body-parser that will create body object for you in your request. To do that
npm install body-parser
var bodyParser = require('body-parser')//add this
app.use(bodyParser())//add this before any route or before using req.body
app.use((req, res) => {
console.log(req.body); // this is what you want
res.on("finish", () => {
console.log(res);
});
});
Ran into this problem but didn't like the solutions. An easy way is to simply wrap the original res.send or res.json with your logger.
Put this as middleware before your routes.
app.use(function responseLogger(req, res, next) {
const originalSendFunc = res.send.bind(res);
res.send = function(body) {
console.log(body); // do whatever here
return originalSendFunc(body);
};
next();
});
https://github.com/expressjs/express/blob/master/lib/response.js
res.send has signature of function(body) { return this; }
Here is a working example using the built in PassThrough stream. Remember to use the express.json() built in middleware to enable request body parsing.
After that, you need to intercept all writes to the response stream. Writes will happen on calling write or end, so replace those functions and capture the arguments in a separate stream.
Use res.on('finish', ...) to gather all the written data into a Buffer using Buffer.concat and print it.
const express = require('express');
const { PassThrough } = require('stream')
const app = express();
app.use(express.json());
app.use((req, res, next) => {
const defaultWrite = res.write.bind(res);
const defaultEnd = res.end.bind(res);
const ps = new PassThrough();
const chunks = [];
ps.on('data', data => chunks.push(data));
res.write = (...args) => {
ps.write(...args);
defaultWrite(...args);
}
res.end = (...args) => {
ps.end(...args);
defaultEnd(...args);
}
res.on('finish', () => {
console.log("req.body", req.body);
console.log("res.body", Buffer.concat(chunks).toString());
})
next();
})
app.use('/', (req, res) => {
res.send("Hello");
});
app.listen(3000);
install npm install body-parser
and use this snippet,
var express = require('express')
var bodyParser = require('body-parser')
var app = express()
// create application/json parser
var jsonParser = bodyParser.json()
to get json response
app.use(jsonParser, function (req, res) {
console.log(req.body); // or console.log(res.body);
})
There is ready made module https://www.npmjs.com/package/morgan-body
const express = require('express')
const morganBody = require("morgan-body")
const bodyParser = require("body-parser")
const app = express()
const port = 8888
// must parse body before morganBody as body will be logged
app.use(bodyParser.json());
// hook morganBody to express app
morganBody(app, {logAllReqHeader:true, maxBodyLength:5000});
app.get('/', (req, res) => {
res.send('Hello World!')
})
app.listen(port, () => {
console.log(`Example app listening at http://localhost:${port}`)
})
Hi was looking for same as complete log of request and response as middleware in express js. Found the solution as well w
/*Added by vikram parihar for log */
const moment = require('moment');
const rfs = require("rotating-file-stream");
const geoip = require('geoip-lite');
const { PassThrough } = require('stream')
let path = require('path');
const accessLogStream = rfs.createStream('access.log', {
interval: '1M', // rotate daily
compress: true,
path: path.join(__dirname, '../../log')
});
module.exports = function (req, res, next) {
try {
let geo = geoip.lookup(req.ip);
let country = geo ? geo.country : "Unknown";
let region = geo ? geo.region : "Unknown";
let log = {
"time": moment().format('YYYY/MM/DD HH:mm:ss'),
"host": req.hostname,
"ip": req.ip,
"originalUrl": req.originalUrl,
"geo": {
"browser": req.headers["user-agent"],
"Language": req.headers["accept-language"],
"Country": country,
"Region": region,
},
"method": req.method,
"path": req.path,
"url": req.url,
"body": req.body,
"params": req.params,
"query": req.query,
"response": {
"body": res.body
}
};
const defaultWrite = res.write.bind(res);
const defaultEnd = res.end.bind(res);
const ps = new PassThrough();
const chunks = [];
ps.on('data', data => chunks.push(data));
res.write = (...args) => {
ps.write(...args);
defaultWrite(...args);
}
res.end = (...args) => {
ps.end(...args);
defaultEnd(...args);
}
res.on('finish', () => {
log.response.body = Buffer.concat(chunks).toString()
accessLogStream.write(JSON.stringify(log) + "\n");
})
} catch (error) {
console.log(error)
next(error)
}
next();
}

Resources