Fetching Wikipedia article via Node.js returns a corrupted response - express

I have some very basic code for getting a Wikipedia page:
router.get("/article-info/:name", async (req, res) => {
// get contents of a wikipedia article
const { data } = await axios.get(
`https://en.wikipedia.org/w/api.php?action=parse&page=${req.params.name}&format=json`
);
console.log(data);
});
But it returns unicode nonsense like:
\u001f�\b\u0000\u0000\u0000\u0000\u0000\u0000\u0003�1%\f�\nnJ<HT齦齁-齖齘X �$�\u0004\u0001\u001a\u00003E�#�\u0004\u0002)w�7齁b88齛牺Z\u0007Y\u001e~>-C齍\u0018\u000f\u0006齘齣|wnw:齫�3齂E�?z淉A颻\\x齃7齴Sdt?_齓1\u000f齓\u0016(M�$](\u000e�,\u00050齠齚稞�!�?u\u001cl�'i\u0012R&�8梌n齣�=jwa\u001f齙�?r\t�<(�&Ur\u001e�7�8�\u0005\u0005J�\u0014�\"gY齰Fx#m齱�\f�$-nr\"齓}�>o齙\u0007齳�,齫xS<o_\r齂U�-9M�\"]=o]�?�K齩&i�\n�\u0003�8Jn齎�7齂d\u0018齊\u0011齙Nh\u0011`\u001a�\u0006g\u001ac\u0018>-\u000b�\"齉\u0017)U�+hRaL\f�\u000b齣齗�\u001bz&齨V\r\u001a齝�-�>v}\u001f鼺�4\u001b}5\u001b3�\u0010齍\f�;齝4qn:�\u000e&R齳�<k齀�,XM鼺\rL\u001du辇齆~[\\+391N^\u0016\u000bvr決B7C\u0019q�0=齮Xu5,齙.齊Gn2(\u000bg鼼]\u001a�\u0011$7l鼸q鼲Q=|�-�\u001bc齰?A齙l齛D�7�7\u001c\u000f泯\r'Jn齣齩\u001f<o<齲;T[fw齷4/MXR齎\u0017�D�\b�'#�\u0013鼳!N�\"K7|9K�4{^dA齋齯9[F齖�6\\�\u0003齲W4\u0003鼳齕齘齍~Ku]�\u001d2\f�\u0017\u001ag鼵]齢k�\u000b齵齳鼶+:{齠\u0013�'�4p�7�\u0000[$齡4齛fO�\u0002zfA6齢\u000ec{�/齗齇F齕z�\b� 齏:�,s齏齣k淉/<;/齰]�\u001fg*u?HuQ>Cs鼺�5齏z齝v^\r-\u0010\u000f齊\u000f齭�\f齇;\nf鼼齇齵w.齍齲�\u0011u�*]妖-�(齧齵\u0019�=齅齸\u0019�>�/><\u000f齕jP#Z齛Z齡3t�5mpi0鼴睚x\bl�\u001d
Going to the URL gives me the result I expect in the browser.
https://en.wikipedia.org/w/api.php?action=parse&page=The_Beatles&format=json

Related

Frontend to Backend POST request is not yielding the data I want

I'm currently working on a project using a React frontend and an Express backend. Currently, when I make a GET request to retrieve data from the backend, everything is working fine. However, I'm unable to POST data to the backend and gain access to the data that's being sent. I'm getting an OK message so the request is going through, but when I log the request data in the backend, I get a message like this which is a jumble of random fields.
Here is the code snippit in the front end for the POST request
const makePost = (data) => {
fetch('http://localhost:5000/api', {
method: 'POST',
headers: {"Content-Type": "application/json", "Access-Control-Allow-Origin": "*"},
body: JSON.parse(JSON.stringify(data))
}).then(function(response){
console.log(response.text())
})
}
Here is my backend which handles the POST request
const express = require('express');
const app = express();
const cors = require('cors');
app.use(cors({
origin: '*'
}));
app.get('/api', (req,res) => {
res.json(menuItems);
});
app.post('/api', (req,res) => {
console.log(req)
})
app.listen(5000, () => console.log("server started on port 5000"));
In the code snippit above, console.log(req) is what was logged in the screenshot linked above.
In your Express server POST API, you are not returning any data, it may cause problems. This is a sample POST API using Axios, Express, React, and MongoDB.Hope it would help you.
//POST API
app.post('/services',async(req,res)=>{
const service = req.body;
const result = await servicesCollection.insertOne(service);
console.log(result);
res.send(result)
});
In client-side POST api:
const onSubmit = data => {
axios.post('http://localhost/services', data)
.then(res=>{
if(res.data.insertedId){
alert('data added successfully');
reset();
}
})
sample post API:
app.post('/book', (req, res) => {
const book = req.body;
// Output the book to the console for debugging
console.log(book);
books.push(book);
res.send('Book is added to the database');
});
Pls take a look at this link: https://riptutorial.com/node-js/example/20967/post-api-using-express

Express 4.17 req.body is being printed as buffer

Something that I wanted clarification on is when console.logging req.body in my express app. I end up with a buffer/string or hexadecimal of some sort when I'm expecting an JSON object. I'm using postman to send a raw json body.
Here are some visuals of the source code and terminal/postman results.
const express = require('express');
const bodyParser = require('body-parser');
const { randomBytes } = require('crypto');
const app = express();
app.use(express.raw({type: "application/json"}));
app.use(express.json({strict: false}));
app.use(express.urlencoded({extended: false}));
const posts = {};
app.get('/posts', (req, res) => {
res.send(posts);
});
app.post('/posts', (req, res) => {
const id = randomBytes(4).toString('hex');
const { title } = req.body;
console.log(req.body)
posts[id] = {
id,
title: title
};
res.status(201).send(posts[id]);
});
app.listen(4000, () => {
console.log('Listening on 4000');
});
Console.log terminal of buffer/hex/string
Postman body
Postman Raw String
app.use(express.raw({type: "application/json"})); is going to give you a Buffer object and since that's your first middleware that might handle that mime type, that's what you're going to get for any application/json request.
Right from the Express doc for express.raw():
This is a built-in middleware function in Express. It parses incoming
request payloads into a Buffer
It's unclear why you're using express.raw() as that is not typical for JSON payloads, but when doing so, you are going to get a Buffer - that's how it works. One would more typically use express.json() for JSON payloads and let it parse your JSON so that req.body contains an actual Javascript object.
If you remove the app.use(express.raw({type: "application/json"})); line of code and let the app.use(express.json()); line of code right after it handle the application/json payloads, then you will get your parsed data in req.body.
Keep in mind that when using middleware they are processed in the order declared and for this specific type of middleware, the first one that matches and reads the body from the incoming stream takes precedence and none of the others after it will be able to do their job (since the incoming stream has already been read).

Why isn't my json data formatted nicely in the browser?

I'm learning Express and I just built a JSON API with CRUD operations to the database
It's working but I'm wondering why my JSON data is formatted like that on the browser
[{"_id":"5f253d105f194d4c8074227d","firstName":"John","lastName":"Doe","age":38,"__v":0},{"_id":"5f253d3a5f194d4c8074227e","firstName":"Jane","lastName":"Doe","age":33,"__v":0}]
I want it to be formatted like
[
{
"_id":"5f253d105f194d4c8074227d",
"firstName":"John",
"lastName":"Doe",
"age":38,
"__v":0},
{
"_id":"5f253d3a5f194d4c8074227e",
"firstName":"Jane",
"lastName":"Doe",
"age":33,
"__v":0}
]
This is the function I use to get the users
router.get("/", async (req, res) => {
try {
const getUsers = await Users.find();
res.json(getUsers);
} catch (err) {
res.json({ message: err.message });
}
});
You only need a JSON formatter for your browser, you can use a formatter like JSON Formatter for Chrome or for JSONView Firefox. Or you can test your API responses with any API client (like Insomnia, Postman, Postwoman...) instead of testing it on your browser
Edit:
If you want (for any reason) to send pre-formatted/human readable JSON responses, you can do so by using JSON.stringify, example:
app.get("/formatted", (req, res) => {
const formattedResponse = JSON.stringify(data, null, 2)
res.type('json').send(formattedResponse)
});

Forward decoded POST data to other URL using Express

Some background information:
I have a temperature sensor which is connected via LoRaWAN.
The data from the sensor is encoded, but the manufacturer of the sensor provides a decoder (node app).
I want to show the data in Thingsboard.
Now I was thinking to build a simple express API (I'm new to Express) as a kind of middleware.
The only purpose is to receive the encoded data, decode it (output is in JSON format), and pass it on to Thingsboard.
With the last step I need some help. This is my route:
const decoder = require('../helpers/decoder');
module.exports = app => {
app.post('/', (req, res) => {
const data = {
type: req.body.productType,
payload: req.body.payloadValue
};
const jsonData = decoder.decode(data.type, data.payload);
// jsonData needs to be forwarded/redirected Thingsboard
});
};
Can anyone point me in the right direction, how to pass on the "handled" POST data and pass it on to another URL (Thingsboard HTTP endpoint URL)
Thanks in advance!
💡 This is not the best practice, but if you want to read some data from some route in another route without passing them when the route was called then you can try this code below: 👇
const express = require('express');
const app = express();
app.post('/', (req, res) => {
app.locals['decoder'] = { data: "This is my decoder data"};
res.send('Successfully to add decoder data');
});
app.get('/', (req, res) => {
res.send(app.locals['decoder']);
} )
app.listen(3000, () => {
console.log('Server is up');
});
⚠️ It should be noted that the code above is only an example of how to read data from one route on another route.
Another option:
👨‍🏫 You can create a middleware that is used to decode your payload and use the middleware on each route that requires the results of the decoded payload.
⚠️ But, it should be noted that for this problem, you must leave a payload on each route that requires decoded results, so that it can be decoded.
Updated: Passing Data To External Endpoint
💡 If You want to pass the data to an external endpoint or another website, see code below: 👇
const axios = require('axios');
app.post('/', (req, res) => {
const decoder = { data: "This is my decoder data"};
// method of external-endpoint: e.g: POST
axios.post('https://www.example-website.com/api/v1/example-endpoint', decoder)
.then(response => {
console.log(response);
}).catch(ex => {
console.log(ex);
})
})
You can use that route above in the example express server in addition to this answer.
I hope it's can help you 🙏.

Supertest and Mongoose Middleware (post remove)

I have been fiddling with this for days, and I cannot figure out why the Mongoose middleware is not being invoked.
So I have an API in node.js and I have a website using Angular.js. The Mongoose middleware is this:
schema.post('remove', function (doc) {
console.log('doctors - post - remove');
});
So this hook is called perfectly fine when invoked from the Angular front end. However, when I run a test with supertest, chai, and mocha the hook is not invoked. Here is my code for the testing:
it('/doctors - POST - (create doctor)', function(done){
request(app)
.post('/doctors')
.send(doctor)
.end(function (err, res){
if (res.body['error']) {
expect(S(res.body['error']).startsWith('doctor already exists')).to.be.true;
}
else
expect(res.body['email']).to.equal(doctor['email']);
done();
});
});
....
it('/doctors/remove - DELETE', function(done){
request(app)
.del('/doctors/remove')
.auth(new_doctor_creds["email"], new_doctor_creds["pass"])
.end(function (err, res){
expect(Object.keys(res.body).length).to.not.equal(0);
done();
});
});
And here is my route for the express app:
app.delete('/doctors/remove', authController.isAuthenticated, function (req, res, next) {
var email = req.user['email'];
Doctors.findOne({email:email}).remove(function (err, removed) {
if (err) return next(err);
return res.status(200).send(removed);
});
});
Again, this Mongoose middleware works perfectly fine when invoked from an API call from the Angular app. However, it does not work when tested with supertest. Any ideas on what to do here?
EDIT: I tried to recreate this example with a simplified version that way you can see all of the code. So here is a two file version that is STILL not working. Here is the app.js:
var mongoose = require('mongoose');
var app = require('express')();
var http = require('http');
var fs = require('fs');
var Doctors = require('./schema');
mongoose.connect('mongodb://localhost/m4', function(err) {
if (err) throw err;
console.log('connected');
app.get('/post', function (req, res, next) {
console.log('create');
Doctors.create({email:"hello"}, function (err, inserted) {
if (err) console.log(err);
res.end();
});
});
app.get('/delete', function (req, res, next) {
console.log('removed');
Doctors.remove({email:"hello"}, function (err, removed) {
if (err) console.log(err);
res.end();
});
});
http.createServer(app).listen('6000', function () {
console.log('now listen on localhost:6000');
});
});
and the schema:
var mongoose = require('mongoose');
var schema = mongoose.Schema({
email: { type: String }
});
schema.pre('save', function (next) {
console.log('doctors - post - save');
next();
});
schema.post('remove', function (doc) {
console.log('doctors - post - remove');
});
module.exports = mongoose.model('Doctors', schema);
Here's what I suggest. Let's perform the #remove on the doc found by #findOne. If I remember correctly, remove post hooks only works on Doc#remove and not on Model#remove.
schema.post('remove', function (doc) {
console.log('doctors - post - remove'); // <-- now runs
});
app.delete('/doctors/remove', authController.isAuthenticated, function (req, res, next) {
var email = req.user['email'];
Doctors.findOne({email: email}, function(err, doc) {
if (err) {
return next(err);
}
doc.remove().then(function(removed) {
return res.status(200).send(removed);
}, function(err) {
next(err);
});
});
});
Mongoose post hooks run AFTER the operation is completed, concurrently with operation callbacks. See the comments below:
Doctors.findOne({email:email}).remove(function (err, removed) {
// All this code and the post hook are executed at the same time
if (err) return next(err);
// Here you send the response so supertest#end() will be triggered
// It's not guaranteed that post remove was executed completely at this point
return res.status(200).send(removed);
});
Post hooks were made to run processes independent of the server response. When you run tests, the server shuts down right after the tests are completed, and maybe it had no time enough to finish the post hooks. In the other hand, when you call the API from a client, normally you keep the server running, so the post jobs can be completed.
Now, there comes a problem: how can we test post hooks consistently? I got up this question because I was looking for a solution to that. If you already have an answer, please post here.