Axios POST requests taking too long and being duplicated at WebApi - ajax

Today I've received bug reports that some of our application's POST requests are being duplicated.
These requests results in the creation of objects on the remote database such like Tasks, Meetings, etc, so the duplication of them implies in Tasks being created with the same name, same due date, user, etc.
I've tried to replicate this but it seems to be a random behavior, and the only concurrent symptom reported is that the request takes more time than normal to complete.
I'm currently using the stack React + Redux + Axios + Asp.Net WebApi, and I have reached to the following considerations in order to understand and solve the issue.
Any tips on any of these topics are really appreciated.
Root cause identification
React + Redux:
The action creator that dispatches the request is called just once, on a onClick event. Apparently there's no state change or page refresh that could cause a multiple call of this fuction.
handleClick(event) {
var postData = {
title: this.state.text,
dueDate: this.state.date,
assignedUser: this.state.user.id
};
this.props.contentPost(postData);
}
Axios:
One of my suspicions is that, for some unknown reason, the users' requests fails, or take to long to complete and then axios supposedly sends the request it again. I've checked it's documentation and issues databases, and didn't found nothing like Automatic Retries or request duplication.
export const contentPost = (props) => {
return function (dispatch) {
dispatch({ type: CONTENT_POST_ERROR, payload: null })
dispatch({ type: CONTENT_POST_LOADING, payload: true });
dispatch({ type: CONTENT_POST_SUCCESS, payload: null })
const request = axios({
method: 'post',
url: `/api/content`,
headers: auth.getHttpHeader(),
validateStatus: function (status) {
return status >= 200 && status < 300; // default
},
data: props
}).then((res) => {
dispatch({ type: CONTENT_POST_LOADING, payload: false });
dispatch({ type: CONTENT_POST_SUCCESS, payload: true, data: res })
}).catch(err => {
dispatch({ type: CONTENT_POST_ERROR, payload: err.code })
dispatch({ type: CONTENT_POST_LOADING, payload: false });
dispatch({ type: CONTENT_POST_SUCCESS, payload: false, data: null })
});
}
};
WebApi
The Controller's method don't have any sort of throttling or "uniqueness token" to identify and prevent duplicated requests. Since this is a random behavior, I would not bet that the Routing or any part of my server side application has any responsibility on this.
Solutions so far...
Axios:
Throttle the axios request at my action creator, to prevent it to be called to often at a given time interval.
Send a client-generated "uniqueness token" in the request body
WebApi
Implement request filtering/throttling, in order to prevent duplicated request, based on body contents at a given time interval.
Receive and handle the "uniqueness token" to prevent post duplicity.
Even with the described above, these solutions looks like an overkill, while the root causes also seems a little too subjective.

I've found out that a late loading state feedback for the users was causing this behavior.
Some people stills double-click stuff on websites. It was naive not to have prevented this by code.
There are a lot of ways to accomplish a better user experience in this scenario. I chose to completely change the button while user are sending our POST request, and we are also implementing the throttling at our backend.
{this.props.content_post_loading &&
<a className="btn btn-primary disabled">Creating...</a>
||
<a className="btn btn-primary" onClick={this.handleCreateClick}>Create</a>
}

Related

How to access API Service for types and mutations from within lambda functions

We are currently working on an application using AWS Amplify. We have 10/15 Lambda functions defined through our Amplify project along with using several other plugins. The project itself is an Angular Application.
Right now, we are working on interfacing some 3rd party services into our Amplify project that utilizes publishing mutations for real time updates using #aws_subscribe. We can trigger these just fine based on the solution using a HTTP request; however, we are wondering if it is possible to reuse the mutation operations already generated within the API.service.ts file to provide consistent typing for both "clients". This will help maintain type control across both "clients" and catch errors earlier. It also prevents us from re-writing mutations/queries down the road.
Our current solution is working but seems inefficient.
Query Statement
const PublishReportingLocationWorkflowProgressUpdateMutation = `mutation PublishReportingLocationWorkflowProgressUpdate( $id: ID!, $status: WorkflowProgressUpdateStatus!, $reportingLocation_id: String! ) { publishReportingLocationWorkflowProgressUpdate(result: {id: $id, status: $status, reportingLocation_id: $reportingLocation_id}) { id status reportingLocation_id } }`;
HTTP Request Body
{
query: PublishReportingLocationWorkflowProgressUpdateMutation,
operationName: 'PublishReportingLocationWorkflowProgressUpdate',
variables: {
id: event.Payload.executionID,
status: 'COMPLETE',
reportingLocation_id: event.Payload.reportingLocation.id }
HTTP Call
let response = await axios({
method: 'POST',
url: process.env.API_URL,
data: mutation,
headers: {
'Content-Type': 'application/json',
'x-api-key': process.env.API_KEY,
}
});

How can I stop external js script from stopping my fetch POST request?

My app generates a custom product page on a Shopify store. I use Vue3 for the frontend. There are other apps running js on the page, e.g. live chat, push notification pop-up, GDPR cookie bar, etc. They are injected by the platform and I can't remove them. (Btw, these js are minified and hard to read)
My app has an add bundle to cart button on the floating footer to send a POST request to my server with Fetch API. But it's blocked by these irrelevant apps. I think these apps are monitoring if a POST / GET request is sent. They assume they are working on standard product pages but not custom one like mine.
I tried to implement a block list with yett. But this passive way is not good enough. It's just a fix after the issue happens. Any way I can protect my fetch request without interfering by other js scripts?
let request = new Request('/create_new_product/', {
method: 'POST',
body: JSON.stringify(data),
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
}
});
let vm1 = this;
fetch(request)
.then(response => response.json())
.then(data => {
console.log('Success creating variant:', data);
console.log('variant_id:', data.variant_id);
// stopped here by other apps :-(
if (data.variant_id) {
vm1.addNewVariantToCart(this.variants, data.variant_id);
vm1.$emit('clearall');
setTimeout(function(){ vm1.isLoading = false; }, 2000);
}
else if (data.Error) {
alert(data.Error);
vm1.isLoading = false;
}
})
.catch((error) => {
console.error('Error:', error);
vm1.isLoading = false;
});

Delete using Yammer API Issue - “Rate limited due to excessive requests.”

While delete a comment, I can delete two comments back to back but when I tried to delete next comment(3rd comment). It shows error in console “Rate limited due to excessive requests.” But after few seconds when I try to delete, it works fine for next two comments. I have tried to use “wait” function for few seconds to make it work but there is inconsistency in result. Sometimes it works and sometimes it doesn’t.
My code as follows,
function deleteComment(MessagePostId) {
var result = confirm("Are you sure you want to delete this Comment?");
if (result) {
yam.platform.request({
url: "https://api.yammer.com/api/v1/messages/" + MessagePostId,
method: "DELETE",
async: false,
beforeSend: function (xhr) { xhr.setRequestHeader('Authorization', token) },
success: function (res) {
alert("The Comment has been deleted.");
//Code to remove item from array and display rest of the comment to screen
},
error: function (res) {
alert("Please try again after some time.");
}
})
}
}
You are hitting rate limits which prevent multiple deletion requests from a regular user like those which you've hit. The API is designed for client applications where you perhaps make an occasional deletion, but aren't deleting in bulk.
To handle rate limits, you need to update your code to check the response value in the res variable. If it's an HTTP 429 response then you are being rate limited and need to wait before retrying the original request.

Can fetch be a substitute for AJAX?

I am wondering if it is possible to do in fetch all the things you can do in traditional ajax?
Because I'm having a problem with a simple login authentication using express. I want to send a response like Login error if the username/password is incorrect, or to redirect the user to the homepage if both is correct, to the client without refreshing the page.
I understand that you can do this in AJAX, but is it possible to do it in fetch also?
I tried using express js and sending a response through a json, but I can't figure out how to handle the response without refreshing the page.
I tried doing it like this in the express server
//if valid
res.json({
isValid: true
})
//if invalid
res.json({
isValid: false
})
And in the client side, specifically in the login page, I have this javascript that handles the submitting of the information
fetch('https://localhost:3000/auth', {
method: 'post',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
username,
password
})
})
.then(response => response.json())
.then(data => {
//I understand that in this part, you can handle the response, but the problem is, I don't know how.
}
})
.catch(console.log)
You are SO close! You've got the fetch, then you've parsed it with response.json, so the next thing is the .then(). In that, you have the JSON object being passed into a param you've named data. All you need to do is check if that has the isValid property!
fetch('https://localhost:3000/auth', {
method: 'post',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
username,
password
})
})
.then(response => response.json())
.then(data => {
if(data.isValid){
// Do something with a valid user. Redirect or whatever.
} else {
// Here, isValid is not set, or is false.
// Send them packing!
}
}
})
.catch(err => console.error("I died: ", err) );
ALSO, take a look at the .catch() block -- in the event of an error, that catches an Error thrown by either the fetch(), or a then(). So you need to add a parameter for the error, and a function body to handle that. I've edited my code sample to demonstrate.
Won't actually run here, but it's formatted all pretty.

ReactJS Redux RxJS AJAX loading indicator

I have a ReactJS & Redux application, and using RxJS for async AJAX with cancellation and error handling. The middleware (for Redux) I am using to connect Redux and RxJS is redux-observable.
I am having a request to the server which also handles errors and cancellation, this is the epic:
const RecipesEpic = action$ =>
action$.ofType(FETCH_RECIPES)
.mergeMap(action => {
return Observable.ajax({
method: "get",
url: url
})
.map(payload => {
return ({ type: FETCH_RECIPES_FULFILLED, payload })
})
.catch(error => Observable.of({
type: FETCH_RECIPES_REJECTED,
payload: error
}))
.takeUntil(action$.ofType(FETCH_RECIPES_CANCELLED))
})
export default RecipesEpic
I'm trying to implement a loading indicator, first I want to log to the console how many percents completed of the request (by using XHR2), and then I will implement the UI. In simple words: How to implement XHR2 download progress in RxJS DOM Request?
I didn't find any resources online about this question, and I hope other people who are searching for this question will have an answer.
Thank you!
According to The RxJS Ajax Documentation you can supply a progressObserver in your Observable.ajax call. The Observer you supply will be updated with the XHR2 download progress!

Resources