Iron Router parse posted values - meteor

I am currently trying to catch posted values from form inside specific route rule.
Since all the other SO posts about this do not work I wanted to ask again.Do you have this sorted out and implemented in your projects?
Is there a solution for Iron-Router#1.0.9?
this.request.body
Above code inside route rule always returns undefined.
Router.route('/register', function(){
console.log( JSON.stringify(this.request.body) );
//this.render('test',{data:{data:this.request.body.username}})
});
//SERVER ONLY
if (Meteor.isServer) {
Meteor.methods({
'addSong': function(songName) {
var userId = Meteor.userId()
songs.insert({
userId: userId,
name: songName
})
}
})
Router.onBeforeAction(Iron.Router.bodyParser.urlencoded({
extended: true
}));
}

The iron router guide lets us know that this.request and this.response are "NodeJS request and response objects".
If you take a look at some documentation for req.body, you will find that:
By default, it is undefined, and is populated when you use
body-parsing middleware such as body-parser and multer.
From Iron-router's guide:
IR makes express' body-parser available at Iron.Router.bodyParser.
So there you have it! If you want this.request.body to be populated, you should maybe add:
Router.onBeforeAction(Iron.Router.bodyParser.urlencoded({
extended: true
}));

I have created one file for my controller to maintain code re-usability name as solar.js under controller folder that solar file has my db functionality and pass the request and response as parameter for that file like exports.getSolarInfo = (req,res) => { console.log(req.body) }, here your will get ur body paramter.then manipulate our functionality here then send response like response = { "status" : 0, "result" : "invalid query" } res.end(JSON.stringify(response));
// importing controller
const SOLAR = require('./controllers/solar.js');
Router.route( '/solar', function() {
//setting header type to allow cross origin
this.response.setHeader( 'Access-Control-Allow-Origin', '*' );
if ( this.request.method === "OPTIONS" ) {
this.response.setHeader( 'Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept' );
this.response.setHeader( 'Access-Control-Allow-Methods', 'POST, PUT, GET, DELETE, OPTIONS' );
this.response.end( 'Set OPTIONS.' );
} else {
SOLAR.getSolarInfo(this.request,this.response);
}
}, { where: 'server' });

Related

How can I disable the bodyparser for one API route method, but enable it for another?

As the question states, how can I disable the bodyparser for one API route method, but enable it for another?
Here's part of my API route:
const handler = async (req, res) => {
if (req.method === "POST") {
...
} else if (req.method === "DELETE") {
...
} else {
res.status(405).json({
data: null,
error: "Method not allowed."
});
return;
};
};
export const config = {
api: {
bodyParser: false,
},
};
export default handler;
You'll see at the bottom of the code block that the body parser applies to both methods at the moment. I need to use the body parser for the DELETE method so that I can access a variable set within the body, but it needs to be disabled for the POST method (handling of multipart forms for image uploads).
I've thought about splitting these into two different files as follows:
Current setup:
/api/advert/[advertId]/image/index.jsx
Potential setup:
/api/advert/[advertId]/image/post.jsx
/api/advert/[advertId]/image/delete.jsx
While this would work, it would deviate the structure from the rest of my code and so I was wondering if there is a cleaner way to achieve this? (Preferably without the use of additional middleware)
Thanks

RTK-Query meta response always empty object

When using RTK-Query to call an API, I need to access a custom header value. I've tried various options for accessing the response headers from the documentation, but all attempts result in an empty object returned:
meta: {
"request": {},
"response":{}
}
I can see in the network tab, that the headers are provided in the response. This is part of a refactor from using raw Axios calls where the header was available from the response object as the headers property.
I've tried accessing the headers through the meta parameter on the transformResponse function of the createApi
transformResponse: (response, meta, arg) => {
console.log(`Transform -> meta: ${JSON.stringify(meta)}`)
// dataKey: meta.response.headers['x-company-data-key'],
return {
...response,
// dataKey
}
}
I've also tried accessing the headers via the meta property of the action parameter from the extraReducers function in the feature slice:
extraReducers: (builder) => {
builder.addMatcher(companyApi.endpoints.getSomeData.matchFulfilled, (state, action) => {
console.log(`action meta: ${JSON.stringify(action.meta)}`)
state.result = action.payload.result
// state.dataKey = action.meta.response.headers['x-company-data-key']
})
}
Both instances result in the meta object that looks like this:
meta: {
"request": {},
"response": {}
}
The API's base query looks like this:
baseQuery: fetchBaseQuery({
baseUrl: process.env.REACT_APP_API_ENDPOINT,
prepareHeaders: ( (headers, { getState }) => {
const realm = getState().companyAuth.realm
if (realm) {
const token = readToken(realm)
if (token)
headers.set('Authorization', `Bearer ${token.access_token}`)
}
return headers
})
}),
and finally, the endpoints definition for this API endpoint:
getCompanyData: builder.query({
query: (params) => {
const { location, page, pageSize } = params
return {
url: `/companies/${location}`,
params: { page, pageSize }
}
}
})
Based on what I could find in the documentation, GitHub issues, and PRs, it seems that the meta property should automatically add the headers, status, and other additional HTTP properties. I'm not sure what I've missed where the response object is completely empty. Is there an additional setting I need to add to the baseQuery?
I should note, that the response data is working properly. I just need the additional information that is returned in the custom header.

How to publish data based on URL in Meteor with Flow Router

I'm trying to publish data specific to the author of a document in my Jobs collection. My route is setup specifically to each unique author, which I then get via FlowRouter.getParam, but it still does not produce any data. I am subscribed to the 'refiJobs' publication but I'm still struggling. Thanks for reading - help is much appreciated!
My Publication
Meteor.publish('refiJobs', function () {
if (Roles.userIsInRole(this.userId, 'admin')) {
var author = FlowRouter.getParam('author');
return Jobs.find({author: author});
} else {
this.error(new Meteor.Error(403, "Access Denied"));
}
});
My route:
authenticatedRoutes.route( '/admin/:author', {
action: function() {
BlazeLayout.render( 'default', { yield: 'user' } );
}
});
The route parameters are not directly available on the server where you are creating your publication. You need to pass your route parameter through to your publication via your subscription as follows:
Client:
Meteor.subscribe('refiJobs',FlowRouter.getParam('author'));
Server:
Meteor.publish('refiJobs',(author)=>{
check(author,String); // be sure to check the parameter(s) to your publication
if (Roles.userIsInRole(this.userId, 'admin')) {
return Jobs.find({author: author});
} else {
this.error(new Meteor.Error(403, "Access Denied"));
}
});

Webhook for Mailgun POST?

I am trying to store email messages as JSON (as parsed by Mailgun) in a Mongo.Collection through a Mailgun webhook. I set up an iron-router server-side route to handle the request, but this.request.body is empty. I am using Mailgun's "Send A Sample POST" to send the request, and the POST looks fine using e.g. http://requestb.in/. I was hoping that request.body would have the data, as mentioned in How do I access HTTP POST data from meteor?. What am I doing wrong?
Router.map(function () {
this.route('insertMessage', {
where: 'server',
path: '/api/insert/message',
action: function() {
var req = this.request;
var res = this.response;
console.log(req.body);
...
I'm not sure that is the right syntax. Have you tried using Router.route ?
Router.route('insertMessage',
function () {
// NodeJS request object
var request = this.request;
// NodeJS response object
var response = this.response;
console.log("========= request: =============");
console.log(request);
// EDIT: also check out this.params object
console.log("========= this.params: =============");
console.log(this.params);
// EDIT 2: close the response. oops.
return response.end();
},
{
where: 'server',
path: '/api/insert/message'
}
);
I think the issue is that Mailgun sends a multipart POST request, e.g. it sends "fields" as well as "files" (i.e. attachments) and iron-router does not set up a body parser for multipart requests. This issue is discussed here and here on iron-router's Github Issues. I found this comment particularly helpful, and now I can parse Mailgun's sample POST properly.
To get this working, in a new Meteor project, I did
$ meteor add iron:router
$ meteor add meteorhacks:npm
In a root-level packages.json I have
{
"busboy": "0.2.9"
}
which, using the meteorhacks:npm package, makes the "busboy" npm package available for use on the server via Meteor.npmRequire.
Finally, in a server/rest-api.js I have
Router.route('/restful', {where: 'server'})
.post(function () {
var msg = this.request.body;
console.log(msg);
console.log(_.keys(msg));
this.response.end('post request\n');
});
var Busboy = Meteor.npmRequire("Busboy");
Router.onBeforeAction(function (req, res, next) {
if (req.method === "POST") {
var body = {}; // Store body fields and then pass them to request.
var busboy = new Busboy({ headers: req.headers });
busboy.on("field", function(fieldname, value) {
body[fieldname] = value;
});
busboy.on("finish", function () {
// Done parsing form
req.body = body;
next();
});
req.pipe(busboy);
}
});
In this way I can ignore files (i.e., I don't have a busboy.on("file" part) and have a this.request.body available in my routes that has all the POST fields as JSON.

Is a server route the right way to do AJAX responses with Meteor/Iron Router

Still trying to get my footing with Meteor. I need an AJAX like method to trigger something on the server and get a response back that it was done.
What I want to do is something like this:
Router.map(function() {
// Remove Blog Posting
this.route('blogRemove', {
path: '/blogRemove/:_id',
where: 'server',
handler: function() {
var request = this.request;
var response = this.response;
// Do some deleting here
}
});
});
This would trigger some server call to remove the blog with the given _id. I would then reply with JSON via the response object. But after 15yrs of development work I have learned: Just because it's possible, doesn't mean it's the right way...
So, the question is: For AJAX-type calls, is this the preferred way to do them in Meteor/Iron Router, or is there some more efficient/elegant way to do them?
Normally you would use a meteor method for that. For instance:
Server:
Meteor.methods({
blogRemove: function (id) {
// delete the blog
return {status: "OK", msg: "removed blog " + id};
}
});
Client:
Meteor.call('blogRemove', id, function(err, result) {
console.log(result);
});

Resources