req.query undefined in Nuxt Express Middleware get request - node.js

Not a pro with things like server middleware, but stuck without much clues.
In a vue component I am retrieving data with axios with this:
axios
.get('/api/getDailyFeedback', {
params: {
start: '2018-05-01'
}
})
Which goes to the express (version 4.16.2) server middleware setup in Nuxt. I have gotten normal get and post requests to work fine but the problem is when I want to pass in a parameter into a get request like the below:
router.get('/getDailyFeedback', (req, res) => {
console.log('Query:', req.query.start);
//do stuff
});
What little experience I had with Express 4, it took me a little bit of time to realise why parameters passed in the body of a post request were undefined, but it was because I needed to add body-parser.json() to my nuxt config since they removed that from the main express package. Similarly I thought I needed bodyParse.urlencoded but that has not worked. This is the line I added to my nuxt.config:
serverMiddleware: [bodyParser.urlencoded({ extended: false }), bodyParser.json(), '~/api'],
I am unsure if the content type is not set correctly or I am missing something simple here. I know I am able to use various libraries to grab the parameters from the url string which I have access to, as Axios is working as expected and adding my 'params' object onto the end of my get request. But a lot of solutions I have seen to other problems is 'oh its as simple as accessing req.query' Alas Express fails to define a req.query object, or even req.params or req.body.
Hopefully that is enough detail to go on, thanks a lot for reading and any suggestions.

Well that's an unpleasant surprise to try to use the get request in Nuxt for the first time, isn't it? Nuxt creates a connect instance which leads to some pitfalls. It's req is the Node.js http request object, so it doesn't have the query property and request.body is also being skipped in get requests!
But there is a way for everything. Your code:
axios.get('/api/getDailyFeedback', {
params: {
start: '2018-05-01'
}
})
Translates to the following URI call:
/api/getDailyFeedback?start=2018-05-01
So you've got all the params in the URI where you can retrieve them from via url parsing. Module url ships with Node.js by the way.
const url = require("url");
router.get('/getDailyFeedback', (req, res) => {
let queryData = url.parse(req.url, true).query
console.log('Query:', queryData.start)
});
I wrote a little helper that extends req with a custom property. Here's the code:
router.use((req, res, next) => {
var theQuery = url.parse(req.url, true).query
req.queryData = theQuery
next()
})
Then you can use it like this:
router.get('/getDailyFeedback', (req, res) => {
console.log('Query:', req.queryData.start)
});
Other way to pass params via get is by using optional uri segments:
router.get('/getDailyFeedback/:start?', (req, res) => {
console.log('Query:', req.params.start)
});

I am using Nuxt 2.15 and I can access the query parameter like this req._parsedOriginalUrl.query

You can access Nuxt get params without additional modules.
Just use:
req.request.get()

For anyone else in the future
const { Router } = require('express')
Router.get('/orders', async (req, res, next) => {
const request = req.query.sometext;
res.json({data: request});
});
module.exports = Router;
<script>
export default() {
async mounted() {
const orders = await axios.get(`/api/orders`, {
params: {
sometext: 'bla bla'
}
});
}
}
</script>
http://expressjs.com/en/api.html#req

Related

problem while POSTing to the server in Express

I'm learning Express and I face an issue which I can't understand.
When I route to /addPerson I expect to log the name: 'Mike', age: 30 to the console. Instead I got nothing logged to the console. What's wrong in my code?
here's the server.js code
const Express = require('express'),
app = Express(),
PORT = process.env.PORT || 5000,
parser = require('body-parser'),
data = []
// initialize the main project folder
app.use(Express.static('public'))
// running the server
app.listen(PORT, () => {
console.log(`Server is running at port ${PORT}`);
})
// include body parser to handle POST requests
app.use(parser.urlencoded({extended: false}))
app.use(parser.json())
// setup CORS
const cors = require('cors')
app.use(cors())
// GET request
app.get('/', (req, res) => {
res.send('<h1>Home Page</h1>')
})
app.get('/addPerson', (req, res) => {
res.send('<h1>Hello Hany</h1>')
})
// POST request
app.post('/addPerson', (req, res) => {
data.push(req.body)
console.log(data);
})
and here is the client side app.js code
const postData = async ( url = '', data = {})=>{
console.log(data);
const response = await fetch(url, {
method: 'POST',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json',
},
// Body data type must match "Content-Type" header
body: JSON.stringify(data),
});
try {
const newData = await response.json();
console.log(newData);
return newData;
}catch(error) {
console.log("error", error);
}
}
postData('/addPerson', {name: 'Mike', age: 30});
this the files structure
Alright, I've taken a look at your code and this is what I've noticed. Within your server.js file you have this code block:
app.get('/addPerson', (req, res) => {
res.send('<h1>Hello Hany</h1>')
})
That is sending back a static H1 tag when the user creates a get request to localhost:5000/addPerson. Then, directly below that you have your post route but you're never fully accessing that from anywhere (I looked through all your app.js code to double check).
Instead, I have changed your code to return a static html file with a button that allows you to call this function (just as an example so you can see that your routes do in fact work). This isn't the cleanest solution to your problem but I just wanted to make sure you see where the problem lies as I've been in your shoes before when I first started working with express. You can take a look at the CodeSandbox I setup below to replicate your issue and take a look through all the code to get an understanding.
To properly solve your issue using the app.js file you would have to serve the javscript file as your "frontend". Personally I'm a big fan of React so I usually serve my frontend with React, while my backend is express. You can also very easily serve this file using NodeJS in a similar fashion that you are with your "backend". If you were to take the React approach you would be able to modify this code:
app.get("/addPerson", (req, res) => {
res.sendFile(path.resolve(__dirname, "public", "index.html"));
});
To find the frontend section you desire using React (I can recommend react-router if you require multiple routes but I don't want to overwhelm you with too much information yet) and complete the same function. If you have any questions feel free to reach out and let me know! Hopefully this helps!

Infinity nodeJS get/post request

So I'm trying to learn nodeJS.. But something wierd is happening. When I try to make a GET or a POST request it keep requesting infinitly on the localhost. I tested with a simple piece of code just requesting a simple Hello Word but it still doesnt works. It was working perfectly yesterday.
I tested insomnia, postman and the browser. If someone can help me would be very nice, cause I'm really stucked here...printscream of the insomnia infinity request
const {json} = require('express');
const express = require('express');
const {uuid} = require('uuidv4');
const app = express();
app.use(express,json);
const projects = [];
app.get('/projects', (request, response) => {
return response.json(projects);
});
app.post('/projects', (request, response) => {
const {title, owner} = request.body;
const project = {id: uuid(), title, owner };
projects.push(project);
return response.json(project);
});
app.listen(3333, () => {
console.log('Working 👏👏')
});
It's just two little mistakes. Take in mind that express.json() is a method, so you need to put it like this:
app.use(express.json())
You are using a comma instead of a point. However, you have done a destructuring of the .json () method; therefore, you do not have to prepend express; it would look like this:
app.use(json())
On the other hand, you probably have an unwanted result in the post request since you send the project variable instead of projects. Be sure that is what you want.

Making req object available to every view file

I have a Node Express web project using Pug views.
By using the Response.locals object, I can make the Express Request object (req in my code) available to every pug file:
const app = require("express")();
app.use((req, res, next) => {
res.locals.req = req;
next();
});
Are there any side effects of using this approach and what are the disadvantages?
The convenience I get is that any view file can have access to all properties of the Request object, eg the query string, etc, without having to pass them explicitly using the textbook method like:
app.get("/xx", (req, res) => {
res.render("xx", { query: req.query });
});
Are there any side effects of using this and what are the disadvantages? Does it use up a lot of memory?
There are no side effects of using a template engine with express. Actually you can use res.render instead.
The convenience I get is that view files can have access to the query string,
If we know req.query has what we need that leaves the question is How to resolve the template for each route?
We will need to split the solution into two parts.
Part One - Genital request handle.
Although the response is dynamic the request resolving is known. Let say we have an additional parameter on the req object req.template and as we sad req.query is available as well.
The below function will render the req.query into req.template and send the response.
function pugTemplateHandler(req, res) {
const compiledFunction = pug.compileFile(req.template);
res.send(compiledFunction(req.query));
}
We don't care about Method nor Routes here. We expect that req to be set before this is called.
Part Two - Resolve the template file according to the route and method
Above we promised pugTemplateHandler that req will be ready for it. We can use Middleware to set the members we need on the req object.
app.get('...', (req, res, next) => {
req.template = 'PUG_TEAMPLATE_PAT'; // resolve template
// req.query = { ... }; // add or overwrite use params
next();
}, pugTemplateHandler); // pass modified req
app.post('...', (req, res, next) => { ... }, pugTemplateHandler);
app.put('...', (req, res, next) => { ... }, pugTemplateHandler);
app.del('...', (req, res, next) => { ... }, pugTemplateHandler);
Because we know the HTTP Method and the Route resolving the template is easy. Most likely here the template will be a static string.
The solution is extendable and has respect the idea of separation of concerns.

Cannot determine why request-promise-native fails on a 'POST with a 404'

I'm trying to make this brief. Hopefully, it isn't so brief it makes no sense. I need to read a list of identifiers from an API that will be used to subsequently 'GET' the JSON files associated with the keys in the list. The list array is stored in another JSON file at the same endpoint with an identifier of 'keys.json' In order to prevent the list from being processed twice, I want to immediately write an empty array back to 'keys.json' upon retrieving it.
Here is the successful function that 'GETS' the list.
const getJsonKeys = async () => {
const options = {
method: 'GET',
uri: baseURL + keysID,
headers: { 'User-Agent': 'Request-Promise' },
json: true // Automatically parses the JSON string in the response
};
return (await rpn(options)).keys;
};
Here is the unsuccessful 'POST' that I try to write with:
const postEmptyJsonKeys = async () => {
const options = {
method: 'POST',
uri: baseURL + keysID,
body: {
keys: []
},
json: true // Automatically stringifies the body to JSON
};
return (await rpn(options)).req.Request.body;
};
Here is the block that calls them both:
module.exports = (rtProcess) => {
rtProcess.get('/process', async (req, res, next) => {
const jsonKeysList = await (getJsonKeys());
console.log("Retrieved Keys", jsonKeysList);
try {
const req = await (postEmptyJsonKeys());
console.log("Wrote", req.Request.body);
} catch(err) {
console.log(err.statusCode, err.error);
console.log(err);
}
//
// more code here
//
jsonKeysList.forEach(courseID => {
//
// more code here
//
});
res.render("process");
}); // end of process route
}; // end of module exports
I have tried everything I know to do to ferret out the answer in the various docs around but I can find nothing that tells me why the catch block is taken, rather than getting a successful try.
BTW the error.status code is a 404.
The error is a string that looks like HTML, which is also a mystery to me since I am trying to POST a simple:
{
keys: []
}
So this error:
Cannot POST /static/quizdata/keys.json
Makes me think the API endpoint you are POSTing to is not properly defined, and that's why you get a 404 It's telling you there is no POST handler that matches that request.
As the question has the node.js tag and I can see the static part in the URL, that makes me think you might be serving that static content with express.static built-in middleware, and if that's the case, then that's why you can't POST anything there, as that middleware is not meant for that and will only take care of GET requests.
Regarding your comment, it's not static content because the route has static in it or because the content it's in a directory called static (if that's the case).
Take a look at this examples:
This will handle GET requests like http.../static/path/inside/public/dir.png:
app.use('/static', express.static('public'));
This will handle GET requests like http.../assets/path/inside/public/dir.png:
app.use('/assets', express.static('public'));
This will handle GET requests like http.../whatever/something/inside/public/dir.png:
app.use('/whatever', express.static('public'));
This will handle GET requests like http.../something/inside/public/dir.png:
app.use(express.static('public'));
This will handle GET requests like http.../something/inside/my-static-files/dir.png:
app.use(express.static('my-static-files'));
You can find more examples in the official docs.
In any case, let's assume you are serving static content using this option:
app.use('/static', express.static('public'));
You can still add another middleware to handle POST requests. Something like this:
const express = require('express');
const fs = require('fs');
const app = express();
const port = 3000;
...
app.post('/static', (req, res, next) => {
// Just an example, you can replace the path and the []
// with anything you want:
fs.writeFileSync('path/to/file.json', JSON.stringify([]));
});
app.use('/static', express.static('public'));
app.listen(port, () => console.log(`Listening on port ${port}!`));
You might also find this other question useful: Appending a JSON file from JS file in Express Application

Dynamically created proxy URL using Node/Express

I want to use express to create unique proxy instances using URLs that I am storing in a database. I found an npm module that may help with this called http-express-proxy but open to other solutions that uses express.
And I had a route like this (using http-express-proxy):
user.URL = 'https://www.google.com'
app.post('/', proxy(user.URL))
// and after this, user.URL is updated to a different value. I want the proxy's address to change too.
I did find a solution that dynamically creates a regular express route during runtime, but I cannot get it to work using the proxy() method from http-express-proxy:
https://alexanderzeitler.com/articles/expressjs-dynamic-runtime-routing/
According to that approach, I can require a 2nd file inside the POST route that looks like this: (and includes a call to the database using sequelize)
const express = require('express')
const proxy = require('express-http-proxy')
const User = require('../db/models/user')
const app = express()
module.exports= {
init : init
}
function init(app) {
User.findOne({where: {id: 1}})
.then(user => app.post('/', proxy(user.URL)))
}
And in my main app.js file, I am then doing this:
// ...
app.post('/', function(req, res, next) {
var dynamic = require('./dynamic')
dynamic.init(app)
})
// ...
But I am getting a 503 response when I post using this approach using http-express-proxy, which was not used in his example.
I got it to work like this. I modified the express-http-proxy module and at the top of the SendProxyRequest() method I included this:
if (req.URL) host = req.URL
And then in my app.js file I added a middleware method to set req.URL after a call to the database:
function getProxyURL (req, res, next) {
User.findOne({where: {id: 1}})
.then(user => {
if(user.URL) req.URL = user.URL
next()
})
}
app.post('/', getProxyURL, proxy('www.default.com'))

Resources