GET request from a local server not working - javascript

I am trying to obtain json files with axios' GET request, but the information is not retrieved.
In index.js (retrieving information):
axios.get('http://localhost:1000/getpost/')
.then((response) => {
console.log(response);
});
Backend endpoint getpost.js (sending information):
var router = require('express').Router();
var Posts = require('../models/post-model.js');
router.route('/').get(() => {
Posts.find({color: "Green"})
.then((res) => {
return res;
});
});
module.exports = router;
I have also tried return Posts.find({color: "Green"}); inside the router.route('/').get... function,
but the value returned is different compared to the one in the promise which is the one I need. I checked that the information is actually sent with console.log(res), but it is not received in the frontend--when I log the result there, it is null.

You are not doing anything with the route response. Maybe something like...
router.route('/').get((req, res1) => {
Posts.find({color: "Green"})
.then((res) => {
res1.end(res);
});
});
(assuming res is the data in plaint text, if it is a JavaScript object you'll do res1.json(res) or res1.jsonp(res))

You need to map the route to getpost as:
router.route('/getpost')
So your getpost would be as:
var router = require('express').Router();
var Posts = require('../models/post-model.js');
router.route('/getpost').get(() => {
Posts.find({color: "Green"})
.then((res) => {
res.send({status:200,message:res});
});
});
module.exports = router;

Apparently, I was not passing the result properly.
The router in getpost.js should be:
router.route('/').get((req, res) => {
Posts.find({color: "Green"})
.then((posts) => res.json(posts));
});

Related

Unhandled Rejection (SyntaxError): Unexpected end of JSON input with Get request fetch

I am trying to do a MVC architecture tutorial from Codecademy's website: https://www.codecademy.com/article/mvc-architecture-for-full-stack-app
I finished the tutorial but when I run everything, I get this error:
It seems that what I'm returning is not valid JSON. So I think the problem is that the endpoint may be causing the error. But I'm not too sure. Here is the code where the error is triggered:
src/utils/index.js:
export const fetchExpenses = async (date) => {
const selectDate = new Date(date).getTime() || new Date().getTime();
const res = await fetch(`/api/expense/list/${selectDate}`);
console.log('result',res);
return res.json();
};
Here is the code from app.js in the "view" portion of my code:
useEffect(() => {
// update view from model w/ controller
fetchExpenses().then((res) => setExpenses(res));
}, []);
It seems the problem is the communication between the view and the controller. When I create an expense, it actually is updated in the database:
Any ideas why this error is happening?
Edit 1:
Here is the network response when I try to create a new expense in my application. So it seems that when I create a new expense, the fetchExpenses() is automatically called to display a list of current expenses.
this the raw response I get from fetchExpenses() :
Edit 2:
Here is what the header shows from the response:
The endpoint is causing the error, but I'm not sure why. Here is the endpoint:
export const createExpense = async (data) => {
const res = await fetch(`/api/expense/create`, {
method: 'POST',
body: data,
});
return resHandler(res, 201);
};
and here is resHandler() which createExpense() returns:
export const resHandler = async (res, status) => {
if (res.status === status) {
return null;
}
const data = await res.json();
if (data && data.emptyFields) {
return data.emptyFields;
}
return null;
};
Here is the code from the controller when an expense is created:
exports.create = (req, res) => {
const form = new formidable.IncomingForm();
form.keepExtensions = true;
form.parse(req, async (err, fields) => {
const { title, price, category, essential, created_at } = fields;
// check for all fields
if (fieldValidator(fields)) {
return res.status(400).json(fieldValidator(fields));
}
try {
const newExpense = await pool.query(
'INSERT INTO expenses (title, price, category, essential, created_at) VALUES ($1, $2, $3, $4, $5)',
[title, price, category, essential, created_at]
);
return res.status(201).send(`User added: ${newExpense.rows}`);
} catch (error) {
return res.status(400).json({
error,
});
}
});
};
Edit 3
Here is the route /api/expense/list/{dateTime}:
const express = require('express');
const router = express.Router();
const { create, expenseById,
read, update, remove, expenseByDate } = require('../controllers');
router.get('/expense/list/:expenseDate', expenseByDate, read);
module.exports = router;
And here is my controllers.js that deal with the route above:
exports.expenseByDate = async (req, res, next, date) => {
try {
const expenseQuery = await pool.query(
'SELECT * FROM expenses WHERE created_at BETWEEN $1 AND $2',
[
startOfDay(new Date(Number(date))).toISOString(),
endOfDay(new Date(Number(date))).toISOString(),
]
);
const expenseList = expenseQuery.rows;
req.expense =
expenseList.length > 0
? expenseList
: `No expenses were found on this date.`;
return next();
} catch (error) {
return res.status(400).json({
error,
});
}
};
exports.read = (req, res) => res.json(req.expense);
The reason you are getting an Unhandled Rejection (SyntaxError): Unexpected end of JSON input error is because your client app is expecting a JSON response and the express app /api/expense/list/{dateTime} route is not returning valid JSON.
The app is not returning valid JSON because the expenseByDate controller callback has an incorrect function signature so it is not getting called.
exports.expenseByDate = async (req, res, next, date) => <-- "date" is not a valid parameter.
This leads the read controller to return an undefined value to the json response.
exports.read = (req, res) => res.json(req.expense); <-- req.expense is undefined.
res.json(undefined) ultimately returns an empty response to the client which can't be parsed and thus an error is thrown.
Solution
You can fix this error by correcting the expenseByDate controller to have a valid function signature by removing the fourth method parameter. To access a route parameter you should use req.params.
exports.expenseByDate = async (req, res, next, date) => {
const date = req.params.expenseDate;
...
}

Send Map in express res.send

I'm working on a game with a friend and we need to send a Map with some stuff in it, but express only sends the user {} instead of the actual Map. The problem is at sending it and not the code itself, console.log'ging it does return the Map.
Code:
router.get("/list", async (req, res) => {
try {
const users = await userCollection.find();
accessedListEmbed(req);
let userData = new Map();
users.forEach((user) => userData.set(user.userName, user.status));
res.send(userData);
console.log(userData);
} catch (error) {
res.send("unknown");
}
});
Generally, you can only send serializable values over the network. Maps aren't serializable:
const map = new Map();
map.set('key', 'value');
console.log(JSON.stringify(map));
Either send an array of arrays that can be converted into a Map on the client side, or use another data structure, like a plain object. For example:
router.get("/list", async (req, res) => {
try {
const users = await userCollection.find();
accessedListEmbed(req);
const userDataArr = [];
users.forEach((user) => {
userDataArr.push([user.userName, user.status]);
});
res.json(userDataArr); // make sure to use .json
} catch (error) {
// send JSON in the case of an error too so it can be predictably parsed
res.json({ error: error.message });
}
});
Then on the client-side:
fetch(..)
.then(res => res.json())
.then((result) => {
if ('error' in result) {
// do something with result.error and return
}
const userDataMap = new Map(result);
// ...
Or something along those lines.

why I am getting undefined when I try to access on my property in node js

I have sent data from frontend to backend when I console what type of requests I have gotten I can see the data is showing into the console but when I try to access those properties I got undefined. I have also tried with a query, body but both get undefined when I try to access the property.
Backend code:
// DELETE SHORT URL
app.delete('/delete/:shortUrl', async (res, req) => {
console.log(req);
console.log(req.params, 'req.params');
})
Frontend:
// DELETE
const deleteUrl = (id) => {
fetch(`http://localhost:5000/delete/${id}`, {
method: 'DELETE'
}).then(res => res.json())
.then(data => {
console.log(data);
if (data.deletedCount) {
alert('Order Deleted')
// const remainingOrders = orders.filter(order => order._id !== id)
// setOrders(remainingOrders)
}
})
.finally(() => setLoadings(false))
}
Based on the Express documentation, the route callback's parameters (req & res) are reversed, so you should have:
app.delete('/delete/:shortUrl', (req, res) => {
console.log(req);
console.log(req.params, 'req.params');
})

How to send message in DELETE route - express.js

I want to show message after deleting user but I don't know how to do it. I tried to create req.session properties and then use them but they are not available in GET route. Do you know how to fix this code?
router.get("/", mid.isExpired, mid.isLoggedIn, mid.isAdmin, (req, res) => {
let currentMessage = req.session.message;
let currentState = req.session.state;
req.session.message = undefined;
req.session.state = undefined;
console.log(currentState, currentMessage); //undefined
user.getAll()
.then(result => {
res.render("users", {
name: req.user,
users: result,
msg: currentMessage,
state: currentState
})
})
});
// delete route
router.delete("/delete/:id", mid.isExpired, mid.isLoggedIn, mid.isAdmin, (req, res) => {
user.del(req.params.id)
.then(() => {
req.session.message = "Some message!"
req.session.state = true;
})
});
// jquery
function ajaxDelete(ev, url) {
ev.preventDefault();
$.ajax({
url: url,
type: "DELETE"
});
}
delBtn.click(function(e) {
var user = $(this).data("user");
ajaxDelete(e, "/users/delete/" + user);
window.location.href = "/users";
})
Use res parameter, and make a variable called message
const message= 'MyMessage';
then
res.json ({message}) // es6 feature
output
{"message":"myMessage"}
In your scenario, as far as I understand you want to send the JSON in response. You can use this code
router.delete("/delete/:id", mid.isExpired, mid.isLoggedIn, mid.isAdmin, (req, res) => {
user.del(req.params.id)
.then(() => {
var response = { message : "Some message!",
state : true };
return res.json(response);
})
});
the keyword 'return' is as per your requirement
router and session are middleware to any nodeJs App,If the router is added before session like this:
app.use(router)
app.use(session(...));
Then the session middleware won't get called for any requests that get handled by router.
Hence change the order of adding router and session middleware,like this
app.use(session(...));
app.use(router)

Send Response in 'then' after Promise resolves

I want to display the json i got from the search for localhost:8400/api/v1/search. But I have no idea how.
I'm using the Elasticsearch Javascript Client
my routing:
'use-strict';
const express = require('express');
const elasticsearch = require('../models/elasticsearch.js');
const router = express.Router();
router.get('/api/v1/search', elasticsearch.search);
for accessing the ElasticSearch DB
const es = require('elasticsearch');
let esClient = new es.Client({
host: 'localhost:9200',
log: 'info',
apiVersion: '5.3',
requestTimeout: 30000
})
let indexName = "randomindex";
const elasticsearch = {
search() {
return esClient.search({
index: indexName,
q: "test"
})
.then(() => {
console.log(JSON.stringify(body));
// here I want to return a Response with the Content of the body
})
.catch((error) => { console.trace(error.message); });
}
}
module.exports = elasticsearch;
Firstly, the route handlers for express routes always have (request, response, next) as it's parameters. You can use the response object to send data back to the client.
Instead of passing the elasticsearch.search method as a route handler, you can write your own route handler and call elasticsearch.search in there, so you still have access to the response object. For example:
function handleSearch(req, res, next) {
elasticsearch.search()
.then(function(data) {
res.json(data)
})
.catch(next)
}
And structure your search function like so:
const elasticsearch = {
search() {
return esClient.search({
index: indexName,
q: "test"
})
.then((body) => body) // just return the body from this method
}
}
This way you separate your concerns of querying elastic and handling the request. You also have access to the request object in case you want to pass any query string parameters from your request to your search function.
Since you add elasticsearch.search as the route handler, it will be invoked with some arguments.
Change the signature of the search method to search(req, res).
Then just call res.send(JSON.stringify(body));
See https://expressjs.com/en/4x/api.html#res for more details

Categories