400 Error when Cloud Code from Twilio - javascript

We've configured our Twilio number to post to the following parse url but it's returning a 400 error: https://myAppId:javascript-key=myJSkey#api.parse.com/1/functions/sendMsgFromTwilio
The parse api says we need a content type header. Does anyone know what the problem might be?
Here's our code:
Parse.Cloud.define("sendMsgFromTwilio", function (req, res) {
//use From phone number param to get client object
ParseUtils.getUserAccount(Crypto.hash(req.params.From)).then(function(result) {
//get providerId from ProviderClient table
var clientId = result.id;
ParseUtils.getProviderClient(clientId).then(function(result) {
var providerId = result.providerId;
//make sure we're actually passing on a message
if(req.params.Body.length > 0) {
var messageType = 0; //text message type
//prepare parameters in hash as done in sendMsg function
var params = {
params : {
providerId: providerId,
clientId: clientId,
payload: {
type: messageType,
content: req.params.Body
}
}
}
//pass message to helper function to send to pubnub
Messaging.sendMsgAsIs(params).then(function (result) {
res.success(result);
}, function (error) {
res.error(error);
});
}
})
});
});
Thanks in advance.

The correct way to implement this is not as a cloud function, but as a custom endpoint. On the hosted Parse solution, this is documented here: https://parse.com/docs/cloudcode/guide#hosting-dynamic-websites
Now with Parse Server, it would be just a standard express route alongside your server. Find out more about Parse Server here: http://blog.parse.com/announcements/what-is-parse-server/

Related

Twilio in nodejs is giving "To: undefined error" and is not able to understand data from front end

I just started using Twilio services and there have been a few challenges. The phone number I send from the front end, I'm not able to make out if its actually being sent to the backend route. Whenever the GET request is done, it throws an error
": Required parameter "opts['to']" missing. twilio".
The first error is what I am getting now.
My form sends this to the backend:
case 2:
const Phoneno = {
phone:countryCode+PhoneNumber
};
axios.post('http://localhost:4000/app/otp', { data :Phoneno });
console.log(Phoneno)
my route for sending otp:
router.post('/otp', async(req, res)=>{
client.verify.v2.services("VERIFY_SERVICE_SID")
.verifications
.create({to:req.body.phone, channel: 'sms'})
.then((verification) => {
console.log(verification.status);
return callback(null);
}).catch((e) => {
console.log(e);
return callback(e);
});
});
In that console.log, I get this,
"{phone: '+91**********'}
phone: "+91**********"(my actual number)
[[Prototype]]: Object"
Also, when I hardcode the phone number, the route works perfectly fine. And when i send an HTTP request to the route, then also it sends an otp to my phone number. But is not able to recognize the data sent from the frontend.
My http request:
POST http://localhost:4000/app/otp
Content-Type: application/json
{
"Phoneno":"+9199********"
}
Please help me out. Thanks a lot for looking into it.
You are making a GET request to your back-end, but you are trying to get the data from the request body. GET requests do not have a body.
You're also trying to send the data by passing it in an object as the second argument to axios.get, but that argument should be a config object. To send the data in the query for the GET request it should be under the params key for that object:
const Phoneno = {
phone:countryCode+PhoneNumber
};
axios.get('http://localhost:4000/app/otp', { params: Phoneno });
Then on the back-end, read the data from the query, using req.query.phone:
router.get('/otp', async(req, res)=>{
client.verify.v2.services(VERIFY_SERVICE_SID)
.verifications
.create({to:req.query.phone, channel: 'sms'})
.then((verification) => {
console.log(verification.status);
return callback(null);
}).catch((e) => {
console.log(e);
return callback(e);
});
However, this might not be a good idea because an attacker can easily create a URL to your site and add the phone number in the query parameters and use it to perform SMS pumping.
I'd actually recommend you change your back-end to a POST request and send the data from the front end in a POST request with the data in the body of the request:
const Phoneno = {
phone:countryCode+PhoneNumber
};
axios.post('http://localhost:4000/app/otp', { data: Phoneno });
router.post('/otp', async(req, res)=>{
client.verify.v2.services(VERIFY_SERVICE_SID)
.verifications
.create({to:req.body.data.phone, channel: 'sms'})
.then((verification) => {
console.log(verification.status);
return callback(null);
}).catch((e) => {
console.log(e);
return callback(e);
});

Redis stream command passing message with parsed value

I am creating the client using Redis and node js, I want to add a message to stream with the below format. I am facing an issue when trying the parse the message with the request body value.
async function userRegister (request) {
var userID = request.body.userID
var username = request.body.userName
redisClient.xadd(
'user:create',
'*',
'module',
`userRegister`,
'request_id',
'2312432434',
'message',
`{"module":"*","user_id":"1","username":"fffff"}`, // this works bcoz its string.
`{"module":"*","userID":"1","username":"here i need pass the above request body value"}`,
function (err, resp) {
if (err) {
console.log(err)
} else {
console.log(resp)
}
}
)
}

Angular2: PUT request to Node-Server doesn't work - authentication lost

I'm using Angular2 on the client side and a node-express server as my backend. The node-server works as an API-middleware and also as my authentication service. The user-requests must contain a valid JWT token to perform requests on the node-server.
All of my GET functions and other PUT functions are working properly. I wrote a new one, which just should delete an ID on a third-party API, doesn't.
Furthermore, my node-express server sends custom error messages at some points to the client. This comes to my problem, whenever I run my latest PUT-function, my server responds with "No token provided". This happens when the user isn't logged in on the client side.
As I said, all my other functions working. this.createAuthenticationHeaders(); is necessary to perform valid request on the server side. But it's implemented.
In other words, the authentication gets lost between client and server and I get my own error message: "No token provided".
Appointment-Detail.Component.ts
cancelAppointment() {
this.authService.getProfile().subscribe(profile => {
this.username = profile.user.username; // Set username
this.email = profile.user.email; // Set e-mail
if (profile.user.email) {
this.apiService.cancelUserAppointment(this.id).subscribe(data => {
console.log(this.id);
if (!data.success) {
this.messageClass = 'alert alert-danger'; // Set error bootstrap class
this.message = data.message; // Set error message
} else {
this.messageClass = 'alert alert-success'; // Set success bootstrap class
this.message = data.message; // Set success message
// After two seconds, navigate back to blog page
}
});
}
});
}
API Service
cancelUserAppointment(id) {
this.createAuthenticationHeaders();
console.log('API SERVICE ' + id);
return this.http
.put(this.domain + 'api/appointments/' + id + '/cancel', this.options)
.map(res => res.json());
}
An API Service functions that works
getCertificatesByUser(email) {
this.createAuthenticationHeaders();
return this.http
.get(this.domain + 'api/user/' + email + '/certificates', this.options)
.map(res => res.json());
}
Server route to the third party API
router.put('/appointments/:id/cancel', (req, res) => {
console.log('hi');
var id = req.params.id;
const url = process.env.acuityUri + '/appointments/' + id + '/cancel';
console.log(id);
});
Authentication middleware
router.use((req, res, next) => {
const token = req.headers['authorization']; // Create token found in headers
// Check if token was found in headers
if (!token) {
res.json({
success: false,
message: 'No token provided'
}); // Return error
} else {
// Verify the token is valid
jwt.verify(token, config.secret, (err, decoded) => {
// Check if error is expired or invalid
if (err) {
res.json({
success: false,
message: 'Token invalid: ' + err
}); // Return error for token validation
} else {
req.decoded = decoded; // Create global variable to use in any request beyond
next(); // Exit middleware
}
});
}
});
Without doing too much of a deep dive into your auth headers, I see a pretty glaring issue that I think may be the cause of your troubles.
HTTP REST verbs carry different "intents", the intent we specifically care about in this case is wether or not your request should have a body.
GET requests do not carry a body with them.
PUT requests do carry a body.
Because of this, angular's HttpClient request methods (http.get, http.post, etc.) have different method signatures.
To cut to the chase, http.put's method signature accepts 3 parameters: url, body, and options, whereas http.get's method signature only accepts 2: url and options.
If you look at your example, for http.put you are providing this.httpOptions as the second parameter instead of the third, so Angular is packaging up your options object as the PUT request body. This is why you have a working example and a non-working example; the working example is a GET!
The solution? Simply put something else as the request body in the second parameter and shift this.options down to the third parameter slot. If you don't care what it is, just use the empty object: {}.
So your request should look like this:
return this.http
.put(this.domain + 'api/appointments/' + id + '/cancel', {}, this.options)
At the very least, this should send whatever is in this.options to the server correctly. Now wether what's in this.options is correct or not is another story.
Example PUT call from Angular's docs: https://angular.io/guide/http#making-a-put-request

Sails + Braintree : Unable to send the transactions details to client

I'm developing an application using Sails JS and Braintree. I'm trying to send the all past transaction details that the customer has made.
Here is my getTransaction action
getTransaction: function(req, res) {
var customerId = req.param('customerId');
var gateway = setUpGateway();
var stream = gateway.transaction.search(function(search) {
search.customerId().is(customerId);
}, function(err, response) {
if (err) {
return res.serverError(err);
}
res.send(response);
});
},
But the problem is, if I directly send the response which I got from braintree server, it throws the circular dependency error. So, to overcome that error I'm fetching only those details that I need from response like this
getTransaction: function(req, res) {
var customerId = req.param('customerId');
var gateway = setUpGateway();
var stream = gateway.transaction.search(function(search) {
search.customerId().is(customerId);
}, function(err, response) {
if (err) {
return res.serverError(err);
}
var transactions = [];
response.each(function(err, transaction) {
var temp = [];
temp.push(transaction.id);
temp.push(transaction.amount);
temp.push(transaction.createdAt);
transactions.push(temp);
});
res.send(transactions);
});
},
But here the .each function is getting executed asynchronously and hence res.send returns the empty array. So what should I do to return all the transaction that the user has made?
Full disclosure: I work at Braintree. If you have any further questions, feel free to contact our support team.
You are correct that the iterator executes asynchronously. You should use Node's stream semantics to process the request
getTransaction: function(req, res) {
var customerId = req.param('customerId');
var gateway = setUpGateway();
var transactions = [];
var stream = gateway.transaction.search(function(search) {
search.customerId().is(customerId);
});
stream.on('data', function (transaction) {
transactions.push(transaction);
});
stream.on('end', function () {
res.send(transactions);
});
},
This will wait until all transactions have been processed before sending the result.
This page provides more information about searching using our Node client library and Node's Stream API.

Saving to MongoDB when Socket.io event is emitted

I'm utilizing a MEAN stack and Socket.io to pull images from the real-time Instagram API. Everything is working great, but I now want to begin saving image data to a MongoDB database so I have a "history" of images from locations (rather than simply the most recent photos).
Below is the relevant (working) code I have so far:
Node server-side code to handle new photo updates from Instagram API and emit event to Angular controller:
// for each new post Instagram sends the data
app.post('/callback', function(req, res) {
var data = req.body;
// grab the object_id (as geo_id) of the subscription and send as an argument to the client side
data.forEach(function(data) {
var geo_id = data.object_id;
sendUpdate(geo_id);
});
res.end();
});
// send the url with the geo_id to the client side
// to do the ajax call
function sendUpdate(geo_id) {
io.sockets.emit('newImage', { geo_id: geo_id });
}
Angular controller code when 'newImage' event is received:
socket.on('newImage', function(geo_id) {
// pass geo_id into Instagram API call
Instagram.get(geo_id).success(function(response) {
instagramSuccess(response.geo_id, response);
});
// Instagram API callback
var instagramSuccess = function(scope,res) {
if (res.meta.code !== 200) {
scope.error = res.meta.error_type + ' | ' + res.meta.error_message;
return;
}
if (res.data.length > 0) {
$scope.items = res.data;
} else {
scope.error = "This location has returned no results";
}
};
});
Angular factory to handle calls to Instagram API:
angular.module('InstaFactory', []).factory('Instagram', function($http) {
var base = "https://api.instagram.com/v1";
var client_id = 'MY-CLIENT-ID';
return {
'get': function(geo_id) {
var request = '/geographies/' + geo_id.geo_id + '/media/recent?client_id=' + client_id;
var url = base + request;
var config = {
'params': {
'callback': 'JSON_CALLBACK'
}
};
return $http.jsonp(url, config);
}
};
});
I also have the following Angular Controller which currently GETS details of each location from my Stadia mongoDB model. This model also contains an (empty for now) 'photos' array that I want to PUSH photo details (url, username, user profile url, etc.) onto each time I receive them from Instagram:
angular.module('StadiaFactory', []).factory('Stadia', function($http) {
var base = "http://localhost:6060/api/stadia/";
return {
'get': function(id) {
var request = id;
var url = base + request;
var config = {
'params': {
'callback': 'JSON_CALLBACK'
}
};
return $http.jsonp(url, config);
}
};
});
This is where I get confused. Where do I fire off the PUT request to my Stadia API and does this Node route for my Stadia API look reasonable? Note: I omitted my GET route which works perfectly. PUT is just throwing me for a loop:
// add photos to stadium photos array
app.put('/api/stadia/:stadium_id', function(req, res) {
// use mongoose to get and update stadium
Stadium.findByIdAndUpdate(req.params.stadium_id,
{$push: {"photos": {img: ?, link: ?, username: ?, profile_picture: ?}}},
{safe: true, upsert: true},
function(err, stadium) {
// if there is an error retrieving, send the error. nothing after res.send(err) will execute
if (err)
res.send(err)
res.jsonp(stadium); // return stadium in JSON format
});
});
Well there are a few problems with your current structure.
When your callback route is called, with a possibility of N objects in it, you're triggering your socket event and retrieving all the last photos of your geography each time. So let's say you will have 3 new objects, you will call 3 times the same thing to get the same data, which is a bit loss when you have the power of the sockets.
You can also have problems if you try to get the object data from the client-side and PUTing it to your server, since all your clients may receive the socket and you could end-up with duplicates, not to mention that this is a lot of traffic for not much, and this will burn your quota API limit, which is also not safe on the client-side since everyone can see your key.
To me, a good way to get something working (even if I don't really know what your :stadium_id param stands for) is to get the info you want directly on the server side in your callback using the request module.
You should only get the pictures, because you can retrieve a lot of things like users, tags or videos that you may don't want to get. So you will have to listen for the image objects, and nothing else.
You could have something like this:
var request = require('request');
var CLIENT_ID = 'yourId';
function newImage(data) {
io.sockets.emit('newImage', data);
}
app.post('/callback', function (req, res) {
//loop in all the new objects
req.body.forEach(function (data) {
if (data.type !== 'image') { return ; }
//BTW I think you should try with the id property instead of object_id
request('https://api.instagram.com/v1/media/' + data.object_id + '?access_token=' + CLIENT_ID,
function (error, response, body) {
if (error) { return ; }
//Here we have one JSON object with all the info about the image
var image = JSON.parse(body);
//Save the new object to your DB. (replace the STADIUM_ID)
Stadium.findByIdAndUpdate(STADIUM_ID, { $push: {'photos':
{ img: image.images.standard_resolution.url,
link: image.link,
username: image.user.username,
profile_picture: image.user.profile_picture
}}},
{ safe: true, upsert: true });
//Send a socket to your client with the new image
newImage({
id: image.id,
img: image.images.standard_resolution.url,
link: image.link,
username: image.user.username,
profile: image.user.profile_picture
});
}
});
res.end();
});
And then in your client, you will only have to push the new images received in the newImage socket event in the $scope.items.

Categories

Resources