Expose return value - rest

I have this piece of code that I am working on. To provide context, I am using an event source to stream an server sent event. Once I receive the data/response I want to pass that into my template(handlebars) view. The code below is a GET request in which I am trying to display the data returned from SSEvents.addEventListener.
method: 'GET',
path: '/students',
config: {
handler: (request, reply) => {
SSEvents.addEventListener('score', function(e) {
const data = JSON.parse(e.data);
}, false);
reply.view('students', {result: data});
},
description: "Endpoint lists all users that have received at least one test score.",
tags: ['api']
}
}
The issue with this code is the constant "data" is not available outside of the scope of the event listener. I need to find a way to expose the constant so that I can use it in reply.view('students', {result: data});
NOTE: I have tried adding "reply.view('students', {result: data});" within the event listener and it throws the following error: reply interface called twice.
Any help would be appreciated.
--Thanks!

It should be working like this. How long it takes your event source to produce an answer? Did you call the reply method twice? This is only one call.
handler: (request, reply) => {
SSEvents.addEventListener('score', function(e) {
const data = JSON.parse(e.data);
return reply.view('students', {
result: data
});
}, false);
},
description: "Endpoint lists all users that have received at least one test score.",
tags: ['api']
}

Related

Twilio Functions work individually but they do not work correctly when I use them in Studio Flows

I have created a couple of functions that work fine by themselves.
Function # 1 - SMS to email. This sends an email upon receipt of SMS at Twilio number:
const got = require('got');
exports.handler = function(context, event, callback) {
const requestBody = {
personalizations: [{ to: [{ email: context.TO_EMAIL_ADDRESS }] }],
from: { email: context.FROM_EMAIL_ADDRESS },
subject: `New SMS message from: ${event.From}`,
content: [
{
type: 'text/plain',
value: event.Body
}
]
};
got.post('https://api.sendgrid.com/v3/mail/send', {
headers: {
Authorization: `Bearer ${context.SENDGRID_API_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify(requestBody)
})
.then(response => {
let twiml = new Twilio.twiml.MessagingResponse();
callback(null, twiml);
})
.catch(err => {
callback(err);
});
};
Function # 2 - Forward SMS. This forwards incoming SMS received at Twilio number to two mobile phone numbers:
exports.handler = function (context, event, callback) {
const twiml = new Twilio.twiml.MessagingResponse();
twiml.message(`From: ${event.From}. Body: ${event.Body}`, {
to: context.ASDA_PHONE_NUMBER,
});
twiml.message(`From: ${event.From}. Body: ${event.Body}``, {
to: context.MY_PHONE_NUMBER,
});
callback(null, twiml);
};
Both functions are working fine when linked directly to the number individually as the only service or function responding to incoming SMS.
However, when I use these functions in a Studio Flow with Run Function widgets they do not work as expected. Function #1 does not work at all. Function #2 works partially, but it seems the event.From and event.Body variables are undefined and the text of the SMS message received by the mobile phones reads "From: undefined. Body: undefined".
This is the structure of the Studio Flow with the two Run Function widgets:
Structure of the Studio Flow with a Run Function widget for each function
It seems context data, like context.MY_PHONE_NUMBER is accesible to the functions. Otherwise the second function would not be able to forward SMS. However it appears event data, like event.From, is not accessible to the functions.
I am guessing the "event" parameter in function(context, event, callback) is not being passed to the functions by the Studio Flow and I need to pass this information as parameters, but I have not found a way to do this.
In the Run Function widget, you can add parameters. These are what will show up on your event object in the Function.
You can use Liquid template syntax for the values to expected keys in your Run Function widget
Twilio support helped me solve this.
I added the following function parameters to the functions:
Function #1:
Key: Body
Value: {{trigger.message.Body}}
Function #2:
Key: From
Value: {{trigger.message.From}}
With that, both functions work perfectly within the flow.

Parse - Sending push notifications using cloud code (Swift)

I'm trying to set up push notifications from one user to another using Back4App which is a parse server. I have followed their guide here
the Javascript cloud code they use is below:
Parse.Cloud.define("pushsample", function (request, response) {
Parse.Push.send({
channels: ["News"],
data: {
title: "Hello from the Cloud Code",
alert: "Back4App rocks!",
}
}, {
success: function () {
// Push was successful
response.success("push sent");
console.log("Success: push sent");
},
error: function (error) {
// Push was unsucessful
response.error("error with push: " + error);
console.log("Error: " + error);
},
useMasterKey: true
});
});
I am updating a custom parse class called notifications within the app which I would also like to send to the user the notification is directed at. When saving this class I am grabbing the UserID which is also stored in the installation class used to send pushes. I am completely new to Javascript so am wondering if someone could tell me how to edit the above code to receive the userID from the method on the device and then run a query to send to just this user.
The push notification feature allows to configure options and customizing the push.
You can send a query to update one specific user. Please, take a look at the example below:
Parse.Cloud.define("sendPushToUser", async (request) => {
var query = new Parse.Query(Parse.Installation);
let userId = request.params.userId;
query.equalTo('userId', userId);
Parse.Push.send({
where: query,
data: {
alert: "Ricky Vaughn was injured in last night's game!",
name: "Vaughn"
}
})
.then(function() {
// Push was successful
}, function(error) {
// Handle error
});
});
At the moment, you can read more about these options here.

How do I Split up batch OData requests

I'm using 'batch' OData requests. However, two separate entity reads are being called in the same request.
How do I split these up into 2 separate batch requests?
E.g.
surveyModel.read("/ResultOfflineSet", {
filters: [
new Filter("QuestionId", FilterOperator.EQ, questionId),
new Filter("JobId", FilterOperator.EQ, self.jobId)
],
success: function(oData, oResponse) {
resolve(oData);
},
error: function (oError) {
reject(false);
}
});
Then later..
// Retreive Category Info and set up panel info.
_.each(oViewData.categories, function(result, index) {
surveyModelCat.read("/CategorySet", {
filters: [
new Filter("CategoryId", FilterOperator.EQ, index)
],
success: function(oDataCategory) {
oViewData.categories[index].categoryId = oDataCategory.results[0].CategoryId;
oViewData.categories[index].categoryDesc = oDataCategory.results[0].CategoryDesc;
oViewData.categories[index].expanded = false;
oViewData.categories[index].complete = false;
oViewModel.setData(oViewData);
resolve(oDataCategory);
},
error: function(oError) {
self.getView().byId("Page1").setVisible(true);
self.busyDialog.close();
}
});
});
When running the app and viewing the Network tab in Chrome, I can see the calls for resultOfflineSet and CategorySet as part of the same $batch request.
Why aren't they in two separate $batches?
Well, there are two things you can try. First the oData model has a setting called useBatch which can be set to false. Otherwise at the end of the read the oData model has a submitBatchRequests method that can be called which would force flush all pending requests that were to be batched together. Either of these should solve the problem.

Sails 1.0 POST route gives 403 error

In my routes.js file, I have defined a route like this:
'PUT /api/v1/entrance/login': { action: 'entrance/login' },
'POST /api/v1/entrance/signup': { action: 'entrance/signup' },
'POST /api/v1/entrance/send-password-recovery-email': { action: 'entrance/send-password-recovery-email' },
'POST /api/v1/entrance/update-password-and-login': { action: 'entrance/update-password-and-login' },
'POST /api/v1/deliver-contact-form-message': { action: 'deliver-contact-form-message' },
'POST /api/v1/getEventsForICalUrl': 'IcalController.getEvents',
I have just used the default generated code and added the last route for getEventsForIcalUrl.
I created an IcalController inside the controllers directory and it has an action getEvents which simply renders a json like this:
module.exports = {
/**
* `IcalController.getEvents()`
*/
getEvents: async function (req, res) {
console.log("hit here");
let events = [];
for (var i = 0; i < 20; i++) {
events.push({foo: "bar" + i});
}
return res.json({
events: events
});
}
};
My problem is that whenever i try to access this controller from the client side, it gives 403 forbidden error.
When I change the route from POST to GET, it works as expected(ofc I am using proper GET/POST request from client end for the route).
Not sure what is breaking.
I also checked the logs. Its printing "hit here" when I use the GET.
In my policy file looks like this(as it was generated. I did not change it):
module.exports.policies = {
'*': 'is-logged-in',
// Bypass the `is-logged-in` policy for:
'entrance/*': true,
'account/logout': true,
'view-homepage-or-redirect': true,
'deliver-contact-form-message': true,
};
And my "is-logged-in" policy file is this:
module.exports = async function (req, res, proceed) {
// If `req.me` is set, then we know that this request originated
// from a logged-in user. So we can safely proceed to the next policy--
// or, if this is the last policy, the relevant action.
// > For more about where `req.me` comes from, check out this app's
// > custom hook (`api/hooks/custom/index.js`).
console.log("req.me=" + req.me);
if (req.me) {
return proceed();
}
//--•
// Otherwise, this request did not come from a logged-in user.
return res.unauthorized();
};
I just put that console.log in this file. others are as they were by default generation from sails new.
The logs show that using POST, this one does not get hit either.(I dont see the "req.me=".. in console.logs.) But this one gets hit when Using GET.
It seems that the route is not working for POST requests. I wonder if its an error in sails js itself or I am doing something wrong.
There are at least two ways how to solve this.
Probably you are using csrf. If you do, your config probably includes this:
module.exports.security = { // With Sails <1.01 this probably is in another file
csrf: true
};
And (if you are using sails v1.01), you should make this route:
'GET /csrfToken': { action: 'security/grant-csrf-token' },
So, to get data on your frontend, you just:
function get_some_records(object_with_data) {
$.get("/csrfToken", function (data, jwres) {
if (jwres != 'success') { return false; }
msg = {
some_data: object_with_data,
_csrf: data._csrf
};
$.post("get_some_records", msg, function(data, status){});
});
}
But if you are using some background jobs, Sails wont give you csrf easily(there is some way probably). So , you just create a route like this:
'post /get_some_records': {
action: 'home/get_some_records',
csrf: false
}
You probably use a Rest client to test (like Postman). Simply disable the csrf protection. in the /config/security.js file
csrf: false

In an isomorphic flux application, should the REST api calls be implemented in the action?

Should it be implemented in the action creator, or in a service class or component? Does the recommendation change if it's an isomorphic web app?
I've seen two different examples:
Action creator dispatches an action login_success/login_failure after making the rest call
Component calls an api service first and that service creates a login_success or failure action directly
example 1
https://github.com/schempy/react-flux-api-calls
/actions/LoginActions.js
The action itself triggers a call to the api then dispatches success or failure
var LoginActions = {
authenticate: function () {
RESTApi
.get('/api/login')
.then(function (user) {
AppDispatcher.dispatch({
actionType: "login_success",
user: user
});
})
.catch(function(err) {
AppDispatcher.dispatch({actionType:"login_failure"});
});
};
};
example 2
https://github.com/auth0/react-flux-jwt-authentication-sample
The component onclick calls an authservice function which then creates an action after it gets back the authentication results
/services/AuthService.js
class AuthService {
login(username, password) {
return this.handleAuth(when(request({
url: LOGIN_URL,
method: 'POST',
crossOrigin: true,
type: 'json',
data: {
username, password
}
})));
}
logout() {
LoginActions.logoutUser();
}
signup(username, password, extra) {
return this.handleAuth(when(request({
url: SIGNUP_URL,
method: 'POST',
crossOrigin: true,
type: 'json',
data: {
username, password, extra
}
})));
}
handleAuth(loginPromise) {
return loginPromise
.then(function(response) {
var jwt = response.id_token;
LoginActions.loginUser(jwt);
return true;
});
}
}
What's the better/standard place for this call to live in a Flux architecture?
I use an api.store with an api utility. From https://github.com/calitek/ReactPatterns React.14/ReFluxSuperAgent.
import Reflux from 'reflux';
import Actions from './Actions';
import ApiFct from './../utils/api.js';
let ApiStoreObject = {
newData: {
"React version": "0.14",
"Project": "ReFluxSuperAgent",
"currentDateTime": new Date().toLocaleString()
},
listenables: Actions,
apiInit() { ApiFct.setData(this.newData); },
apiInitDone() { ApiFct.getData(); },
apiSetData(data) { ApiFct.setData(data); }
}
const ApiStore = Reflux.createStore(ApiStoreObject);
export default ApiStore;
import request from 'superagent';
import Actions from '../flux/Actions';
let uri = 'http://localhost:3500';
module.exports = {
getData() { request.get(uri + '/routes/getData').end((err, res) => { this.gotData(res.body); }); },
gotData(data) { Actions.gotData1(data); Actions.gotData2(data); Actions.gotData3(data); },
setData(data) { request.post('/routes/setData').send(data).end((err, res) => { Actions.apiInitDone(); }) },
};
In my experience it is better to use option 1:
Putting API calls in an action creator instead of component lets you better separate concerns: your component(-tree) only calls a "log me in" action, and can remain ignorant about where the response comes from. Could in theory come from the store if login details are already known.
Calls to the API are more centralized in the action, and therefore more easily debugged.
Option 2 looks like it still fits with the flux design principles.
There are also advocates of a third alternative: call the webAPI from the store. This makes close coupling of data structures on server and client side easier/ more compartmental. And may work better if syncing independent data structures between client and server is a key concern. My experiences have not been positive with third option: having stores (indirectly) create actions breaks the unidirectional flux pattern. Benefits for me never outweighed the extra troubles in debugging. But your results may vary.