MobX State Tree generator does not allow modified state in a successful promise? - generator

Via the code following I get this error:
error: Error: [mobx-state-tree] Cannot modify
'AuthenticationStore#<root>', the object is protected and can only be
modified by using an action.
the code (generator) in question:
.model('AuthenticationStore', {
user: types.frozen(),
loading: types.optional(types.boolean, false),
error: types.frozen()
})
.actions(self => ({
submitLogin: flow(function * (email, password) {
self.error = undefined
self.loading = true
self.user = yield fetch('/api/sign_in', {
method: 'post',
mode: 'cors',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
'user' : {
'email': email,
'password': password
}
})
}).then(res => {
return res.json()
}).then(response => {
self.loading = false // the error happens here!
return response.data
}).catch(error => {
console.error('error:', error)
// self.error = error
})
}), ...
The question: is this not permitted in a generator, is there a better way to update this particular state or does it need to be wrapped by a try/catch?
As always thanks is advance for any and all feedback!

The problem is you're calling then on the Promise returned by fetch(), and the function you pass to then is not an action. Note that functions that run within an action (or flow) do not count as the action itself.
Since you're using yield, you don't need to call then or catch on the Promise returned by fetch(). Instead, wrap it in a try/catch:
submitLogin: flow(function* (email, password) {
self.error = undefined;
self.loading = true;
try {
const res = yield fetch('/api/sign_in', {
method: 'post',
mode: 'cors',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
'user' : {
'email': email,
'password': password
}
})
});
const response = yield res.json();
self.loading = false;
self.user = response;
} catch(error) {
console.log('error: ', error);
self.error = error;
}
}

Related

Why is my Response of Type Vague on this google cloud function?

I am calling a Google Cloud Function. I have a green arrow beside the function. I have enabled it to use HTTP. I have enabled it to work without authorization.
When I call it I get an error 403 and an object that says response type opaque. I have no idea what is wrong now ...
I have spent an entire day on this. And I'm so confused.
I'm calling it from both localhost:3000, and from an app I built on https://djit.su/
I have tried my best to figure out the CORS and everything else, but I am so stuck.
At this point I just want it to return "hey" to my local machine...
Here is my Google Cloud FN:
'use strict'
const functions = require('firebase-functions');
const cors = require('cors')({
origin: true,
});
exports.date = functions.https.onRequest((req, res) => {
console.log('Made it to here!');
if (req.method === 'PUT') {
return res.status(403).send('Forbidden!');
}
return cors(req, res, () => {
const stringVar = 'This is a string var';
console.log('Hi from inside cloud fn');
console.log('Sending:', { name: "Hi I'm Rick", stringVavr: stringVar });
const options = {
secure: false,
signed: false,
sameSite: None,
};
res.cookie('session', 'ABCE', options);
res.set('Access-Control-Allow-Methods', 'GET');
res.set('Access-Control-Allow-Headers', 'Content-Type');
res.set('Access-Control-Max-Age', '3600');
res.header('Access-Control-Allow-Origin', '*');
res.set('Access-Control-Allow-Origin', '*');
if (req.method === 'OPTIONS') {
res.set('Access-Control-Allow-Methods', 'GET');
res.set('Access-Control-Allow-Headers', 'Content-Type');
res.set('Access-Control-Max-Age', '3600');
res.status(204).send('');
}
});
});
Here is my React code:
async function getNum() {
await fetch(
'https://us-central1-provable-fair-algo-rick.cloudfunctions.net/randomHash',
{ mode: 'no-cors' }
)
.then(function (response) {
// return response.text();
console.log(response);
console.log(json.response);
Promise.resolve(response);
console.log(Promise.resolve(response));
})
.then(function (text) {
console.log('Request successful', text);
})
.catch(function (error) {
console.log('Request failed', error);
});
Here is the console.log
Response {type: "opaque", url: "", redirected: false, status: 0, ok: false, …}
body: (...)
bodyUsed: false
headers: Headers {}
ok: false
redirected: false
status: 0
statusText: ""
type: "opaque"
url: ""
The issue seems to be on your react code, as you are using { mode: 'no-cors' } however the Cloud Function is using CORS as it is in a different domain.
Here it explains that using no-cors can generate this opaque response:
no-cors is intended to make requests to other origins that do not have CORS headers and result in an opaque response, but as stated, this isn't possible in the window global scope at the moment.
A way to correct this would be to use: { mode: 'cors' } The code will be as the following:
function getNum() {
await fetch(
'https://us-central1-provable-fair-algo-rick.cloudfunctions.net/randomHash',
{ mode: 'cors' }
)
.then(function (response) {
// return response.text();
console.log(response);
console.log(json.response);
Promise.resolve(response);
console.log(Promise.resolve(response));
})
.then(function (text) {
console.log('Request successful', text);
})
.catch(function (error) {
console.log('Request failed', error);
});

node js stops working on multiple api request from angular and working after restarting the node app

i am developing an app with node express js and angular js. My angular app makes an api request from node js app server on each route or button click, also a single component or button click may request multiple api to node js app. upon requesting multiple time the data loading is just got stopped and i am not getting result. Also getting status code like 304 and 204.
please check out my api code and subscribe service code.
constroller.js ///express js
getList: async (req, res) => {
try{
const result = await getList(); //from service.js (an sql query)
var serviceCalls = result[0][0];
return res.set({'Content-Type': 'application/json'}).status(200).json({
success: 1,
message: 'Successfully Data Fetched',
data: serviceCalls
});
} catch(e){
return res.json({
success: 0,
message: 'No Data Fetched' + ' ' + e.message,
data: {}
});
}
},
getDetails: async (req, res) => {
try{
const id = req.query.id
const result = await getDetails(id); //from service.js (an sql query)
var serviceCalls = result[0][0];
return res.set({'Content-Type': 'application/json'}).status(200).json({
success: 1,
message: 'Successfully Data Fetched',
data: serviceCalls
});
} catch(e){
return res.json({
success: 0,
message: {text:'No Data Fetched ', errMsg: e.message},
data: {}
});
}
},
getTroubles: async (req, res) => {
try{
const id = req.query.id
const result = await getTroubles(id); //from service.js (an sql query)
var complaintData = result[0][0];
return res.set({'Content-Type': 'application/json'}).status(200).json({
success: 1,
message: 'Successfully Data Fetched',
data: complaintData
});
} catch(e){
return res.json({
success: 0,
message: 'No Data Fetched',
data: []
});
}
},
getLogs: async (req, res) => {
try{
const id = req.query.id
const result = await getLogs(id); //from service.js (an sql query)
var feedbackData = result[0][0];
return res.set({'Content-Type': 'application/json'}).status(200).json({
success: 1,
message: 'Successfully Data Fetched',
data: logs
});
} catch(e){
return res.json({
success: 0,
message: {text:'No Data Fetched ', errMsg: e.message},
data: []
});
}
},
routes //node js express js
app.js
app.use('/serviceCall', serviceCallRoute);
serviceCallRoute
router.get("/getList", getList);
router.get("/getDetails", getDetails);
router.get("/getTroubles", getTroubles);
router.get("/getLogs", getLogs);
angular subscribe to api
getServiceCalls() {
return this.http.get(url + 'serviceCall/getList',this.httpOptions)
.pipe(
map((res: IServiceCall) => {
return res;
}),
catchError(errorRes => {
return throwError(errorRes);
})
);
}
getServiceCallDetails(id):Observable<IServiceCall> {
const params = new HttpParams().set('id', id);
const headers = new HttpHeaders({ 'Content-Type': 'application/json'})
return this.http.get(url + 'serviceCall/getDetails',{headers:headers,params: params})
.pipe(
map((res: IServiceCall) => {
return res;
}),
catchError(errorRes => {
return throwError(errorRes);
})
);
}
getServiceCallTroubles(id) {
const params = new HttpParams().set('id', id);
const headers = new HttpHeaders({ 'Content-Type': 'application/json'})
return this.http.get<IServiceCallTroubles>(url + 'serviceCall/getTroubles',{headers:headers,params: params})
.pipe(
map((res: IServiceCallTroubles) => {
return res;
}),
catchError(errorRes => {
return throwError(errorRes);
})
);
}
getServiceCallLogs(id):Observable<IServiceCallLogs>{
const params = new HttpParams().set('id', id);
const headers = new HttpHeaders({ 'Content-Type': 'application/json'})
return this.http.get<IServiceCallLogs>(url + 'serviceCall/getLogs',{headers:headers,params: params})
.pipe(
map((res: IServiceCallLogs) => {
return res;
}),
catchError(errorRes => {
return throwError(errorRes);
})
);
}
The express js is working well. It is fault in database connection limit.
the DB connection limit was set as 10. So,after 10 api request with sql query. The db connection gets disconnected.

'fetch' from router - how to have 'res.status(400).json('Enter failure message here')' be handled as an error in .then .catch?

I have the following code as part of a Button in one of my React Native components. Observe how there is no .catch to handle a possible 'no results' case from server; it is handled with if-statements instead (e.g.: else if (acceptMatchRequestData['status']==='failure') which I was what I'm trying to get away from.
await acceptMatchRequest(match['matchId'], userId, getUserInfoData[0]['ratings'][matchType])
.then(acceptMatchRequestData => {
if (acceptMatchRequestData['status']==='success') {
setMatchInvites(prevState => {
return prevState.filter((observation, i) => observation['matchId'] !== match['matchId'])
})
setMatchScreenParentState('loading')
sendToUserDeviceNotification('matchFound', userId, match['matchedUserId'])
} else if (acceptMatchRequestData['status']==='failure') {
Alert.alert('', acceptMatchRequestData['message'])
}
})
acceptMatchRequest function code:
export async function acceptMatchRequest(matchId, userId, rating) {
console.log('Attempting to accept match request');
info = { matchId, userId, rating }
const firebaseIdToken = await AsyncStorage.getItem('#firebaseIdToken')
const requestOptions = {
method: 'POST',
headers: { 'Content-Type': 'application/json', 'Authorization': 'Bearer ' + firebaseIdToken },
body: JSON.stringify(info)
};
const response = await fetch(ngrokOrLocalhost + '/acceptmatchrequest', requestOptions)
const data = await response.json()
return data
}
And server code:
router.post('/acceptmatchrequest', async (req, res) => {
const { matchId, userId, rating } = req.body;
const results = await Match.find({ 'usersInfo.userId': userId, 'matchRecords.matchConfirmed': { $nin: [true] } }).limit(5)
if (results.length===5) {
res.status(400).json({'status': 'failure', 'message': 'You already have 5 active matches. Please finish a match first before you can accept this match.'})
} else {
var filter2 = { '_id': matchId }
var update2 = { 'isCustomRequest_IsAccepted': true, '$push': { 'usersInfo': { 'userId': userId, 'location': { 'type': 'Point', 'coordinates': [0, 0] }, 'rating': rating } } }
var response2 = await Match.findOneAndUpdate(filter2, update2, { new: true, sort: { 'matchCreatedTimestamp': 1 } })
if (response2) {
// Document was updated
res.status(200).json({'status': 'success', 'message': 'Match request was accepted successfully'})
} else {
console.log('Match request was not accepted successfully');
res.status(400).json({'status': 'failure', 'message': 'Match request was not accepted successfully'})
}
}
})

TypeError: JSON.stringify(...).then is not a function - React JS

I am trying to connect my react app with the backend for log in page. I am using a promise to return a success message.
login.js
onSubmitSignIn = () => {
fetch('http://localhost:5000/', {
method : 'post',
headers :{ 'Content-Type' : 'application/json'},
body : JSON.stringify({
userId : this.state.userId,
password : this.state.password
}).then(response => response.json())
.then(data => {
if(data === 'success'){
this.props.onRouteChange('home');
}
})
})
}
Backend code -
exports.findById = (req) => {
return new Promise((resolve) => {
var sql = "Select * from users where userid = '" + req.body.userId + "' ;";
connection.query(sql,req, function (error, results, fields) {
var data = JSON.parse(JSON.stringify(results));
var valid = false;
if( data.length !=0 && req.body.userId === data[0].userid && req.body.password === data[0].password)
valid = true;
if(valid) {
resolve({message : "success"});
}else{
reject({ message :"fail"});
}
});
})
};
After clicking on sign in button, I am getting an error "TypeError: JSON.stringify(...).then is not a function"
I tried some solutions from similar questions, it did not work in my case.
The then should be outside of fetch
fetch('http://localhost:5000/', {
method : 'post',
headers :{ 'Content-Type' : 'application/json'},
body : JSON.stringify({
userId : this.state.userId,
password : this.state.password
})
}).then(response => response.json())
.then(data => {
if(data === 'success'){
this.props.onRouteChange('home');
}
})
You have a typo, .then should be on fetch not on JSON.stringify.
onSubmitSignIn = () => {
fetch("http://localhost:5000/", {
method: "post",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
userId: this.state.userId,
password: this.state.password
})
})
//-^
.then(response => response.json())
.then(data => {
if (data === "success") {
this.props.onRouteChange("home");
}
});
};
you have missed a bracket. there should be a closing bracket after JSON.stringify().
onSubmitSignIn = () => {
fetch('http://localhost:5000/', {
method: 'post',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
userId: this.state.userId,
password: this.state.password
})
}).then(response => response.json())
.then((data) => {
if (data === 'success') {
this.props.onRouteChange('home');
}
});
};
I had this problem too. Check and confirm that you're not importing or requiring {JSON} in your application. It's most likely referring to that imported JSON rather than the global

HTTP Post request with credentials and form in nodejs

I want to make an HTTP POST request to a server with credentials (username, password) and content.
More specifically, I used various approaches without success. One of them is:
var request = require('request');
request({
url: 'https://path',
method: 'POST',
auth: {
user: 'username',
pass: 'password'
},
form: {
'grant_type': 'client_credentials',
'text' : 'input-text',
'features': {
'score': true,
}
}
}, function(err, res) {
console.log(res);
var json = JSON.parse(res.body);
console.log("Access Token:", json.access_token);
});
Do you have any suggestion?
I feel more comfortable using promises. request-promise documentation
var request = require('request-promise');
var options = {
method: 'POST',
url: '',
auth: {
user: '',
password: ''
},
headers: {
'': ''
},
json: true
}
return request(options)
.then(function (response) {
// manipulate response
}).catch(function (err) {
return err
})