How can I make 1 million+ requests to an API in React appication? - reactjs

I'm trying to make a large number of post requests to an API and create "service tickets".
I have 3 types of services and I want to create packages of 50, 100, 500, 1k, 10k, and 1Million depending of what the user selects. (I am already storing that in a React State)
When I click I button I would like to send all the requests for the tickets at once, so we can have at the end:
service 1 = 1,000,000 tickets
service 2 = 500 tickets
service 3 = 1,000,000 tickets
total of Tickets = 2,000,500
I was wondering what is the best way to handle that amount of post requests in a single click? Any help will be very useful. Thanks!
This is the function I'm passing to my onClick event that creates a single ticket:
const addTicket = async () => {
try {
const token = await getTokenSilently(); // from auth0 authentication
let url = '.../endpoint'
const post = {
createdFor: hostId, // here I put the id of the user I want to add the tickets
service: typeOfService // Here I select one of the 3 types of services
}
const response = await fetch(url, {
method: 'POST',
body: JSON.stringify(post),
headers: {
"Authorization": "Bearer "+ token
}
});
const responseData = await response.json();
} catch (error) {
console.error(error);
}
};
Im using:
-"react": "^16.13.1"
-the backend is running AWS Lambda

A million requests are not required, you can make an API endpoint where you can make 1 request with information of how many tickets you want and then handle the number of tickes on the server-side.
If you will make 1 million requests you will need a much better server and resources and you will be wasting a lot of unnecessary money

Related

Is there a way to get a download percentage from a fetch request in React?

I am looking for a way to get the progress of a fetch request in my React app? Is there any way to plug into the fetch API to get some type of percentage loaded of the request that I can use to display to my users?
Using fetch method
To track download progress, we can use response.body property.
It’s a ReadableStream – a special object that provides body chunk-by-chunk, as it comes.
Readable streams are described in the Streams API specification.
Unlike response.text(), response.json() and other methods, response.body gives full control over the reading process, and we can count how much is consumed at any moment.
// Start the fetch and obtain a reader
let response = await fetch(url);
const reader = response.body.getReader();
// get total length
const contentLength = +response.headers.get('Content-Length');
// read the data
let receivedLength = 0; // received that many bytes at the moment
let chunks = []; // array of received binary chunks (comprises the body)
while(true) {
const {done, value} = await reader.read();
if (done) {
break;
}
chunks.push(value);
receivedLength += value.length;
console.log(`Received ${receivedLength} of ${contentLength}`)
}
Please note currently upload track is not possible in fetch method. For that we should use XMLHttpRequest.
Reference : https://javascript.info/fetch-progress
Using axios class :
axios.request({
method: "post",
url: url,
data: data,
onUploadProgress: (p) => {
console.log(progress);
}
}).then (data => {
})

What's the best way to store a HTTP response in Ionic React?

I'm developing an app with Ionic React, which performs some HTTP requests to an API. The problem is I need to store the response of the request in a local storage so that it is accessible everywhere. The way I'm currently doing it uses #ionic/storage:
let body = {
username: username,
password: password
};
sendRequest('POST', '/login', "userValid", body);
let response = await get("userValid");
if (response.success) {
window.location.href = "/main_tabs";
} else if (!response.success) {
alert("Incorrect password");
}
import { set } from './storage';
// Handles all API requests
export function sendRequest(type: 'GET' | 'POST', route: string, storageKey: string, body?: any) {
let request = new XMLHttpRequest();
let payload = JSON.stringify(body);
let url = `http://localhost:8001${route}`;
request.open(type, url);
request.send(payload);
request.onreadystatechange = () => {
if (request.readyState === 4 && storageKey) {
set(storageKey, request.response);
}
}
}
The problem is that when I get the userValid key the response hasn't come back yet, so even awaiting will return undefined. Because of this I have to send another identical request each time in order for Ionic to read the correct value, which is actually the response from the first request. Is there a correct way of doing this other than just setting timeouts everytime I perform a request?
You are checking for the results of storage before it was set. This is because your sendRequest method is calling an asynchronous XMLHttpRequest request, and you are checking storage before the sendRequest method is complete. This can be fixed by making sendRequest async and restructuring your code a bit.
I would suggest you instead look for examples of ionic react using hooks or an API library - like fetch or Axios. This will make your life much easier, and you should find lots of examples and documentation. Check out some references below to get started:
Example from the Ionic Blog using Hooks
Example using Fetch using React
Related Stack Overflow leveraging Axios

How to perform a post request with axios on React and pass your data as FormData?

There's this API:http://zssn-backend-example.herokuapp.com/api/, detailed here: http://zssn-backend-example.herokuapp.com/swagger-api/index.html#!/people/Api_People_index . I am trying to do a POST request on this endpoint "/people/{person_id}/properties/trade_item.json"(Make a trade transaction between survivors). On the Website for testing I filled the fields with the following data and got 204 response:
person_id:34e183a6-965e-4a61-8db5-5df9103f4d4b
consumer[name]: Person4
consumer[pick]: AK47:1;Campbell Soup:1
consumer[payment]: First Aid Pouch:2
I investigated a Little and got
this information
didn't understand the "PROPERTY[KEY]:VALUE" representation
When I try to the Request with this code, with the same values(by the way, the database of this API is cleared each 24 hours, so those value might not work, even if you do it in the right way):
this is My code:
async function handleTrade(e){
e.preventDefault();
const config = {
headers: {
"Content-Type": "application/x-www-form-urlencoded",
},
};
await api.post(
"/people/" + match.params.id + "/properties/trade_item.json",
{
person_id:match.params.id,
name: survivorRef.current,
pick: survivorItemsToPick,
payment: userItemsToPay,
},
config
);
And this is what I get:
Request:
request-description
Response:
response-description
How Can i make this request in the right way in order to get the same result as the first Image ?
You can use FormData to send the request, I made an example:
const data = new FormData();
data.append("customer[name]", "Person4");
data.append("customer[pick]", "AK47:1");
await api.post("/people/" + match.params.id + "/properties/trade_item.json", data, config)

Fetch status 200 but pending endllessly, except first call

I've been searching to solve this problem for a while but couldn't find a working solution.
I'm making a simple social network website and this API returns a article data such as text, image and video url, etc, all saved in server's local MySQL Database. My front-end is React and server is Nginx reverse proxy with Node.js using Express. When I load the page, I create 5 React components that each make fetch request for given article number.
The following code snippet is the fetch API that asks the server to fetch data from database:
//server-side script
app.get('/api/getArticle/:id', (req, res) => {
const con = mysql.createConnection({
host: 'myhost_name',
user: 'myUser',
password: 'myPassword',
database: 'myDB',
});
con.connect(function (err) {
if (err) {
throw err;
}
console.log("Connected!");
})
const idInterest = req.params.id.toString();
console.log(idInterest)
let sql = 'some_sql';
con.query(sql, function (err, result) {
if (err) {
res.status(500).send("Error while getting article data");
return;
}
else {
res.set('Connection', 'close')
res.status(200).send(result);
console.log("ended")
con.end();
return;
}
})
}
//React script
//index.js
fetch('http://mywebsite.com/api/getMaxArticleId/')//Retrieve top 5 article ID
.then((response) => {
for (let i = 0; i < data.length; i++) {
nodesList.push(<Container articleId={data[i]['id']}/>)
}
ReactDOM.render(<React.StrictMode><NavBar />{nodesList}<Writer writer="tempWriter" /></React.StrictMode>, document.getElementById('root'));
})
//Container.jsx; componentDidMount
const url = "http://mywebsite.com/api/getArticle/" + this.props.articleId.toString();
fetch(url, {
method: 'GET',
credentials: "include",
}).then((response) => {
response.json().then((json) => {
console.log(json);
//processing json data
This used to work very fine, but suddenly the getArticle/:id calls started to show 200 status but 'pending' in 'time' column in Chrome network tab, endlessly, all except the first*getArticle/:idcall. This prevents my subsequent .then() in each Container from being called and thus my entire tab is frozen.
Link to image of network tab
As you see from the image, all pending fetches are missing 'Content Download' and stuck in 'Waiting(TTFB)', except the first call, which was '39'
I checked the API is working fine, both on Postman and Chrome, the server sends result from DB query as expected, and first call's Json response is intact. I also see that console.log(response.json()) in React front-end shows Promise{<pending>} with *[[PromiseStatus]]: "Resolved"* and *[[PromiseValue]]* of Array(1) which has expected json data inside.
See Image
This became problematic after I added YouTube upload functionality with Google Cloud Platform API into my server-side script, so that looks little suspicious, but I have no certain clue. I'm also guessing maybe this could be problem of my React code, probably index.js, but I have no idea which specific part got me so wrong.
I've been working on this for a few days, and maybe I need common intelligence to solve this (or I made a silly mistake XD). So, any advices are welcomed :)

redux-api sync action inside a prefetch block

I am coding a SPA in react.js and I am using redux-api to handle backend connection. I want to do a sync action to refresh the auth token before doing the main action; this way, every time I will do an action to the backend I will be sure that the token is valid.
const endpoints = {
{
url: '/some/url',
crud:true,
prefetch:[
({actions, dispatch, getState}, cb) =>{
actions.auth_token.post(JSON.stringify({
token: "my token",
refreshToken: "my_refresh_token"
}),null, (err, data) =>{
if(err){
// HANDLE ERROR
}
setToken(data)
})
}
]
}
}
const api = reduxApi(endpoints)
How can I call the prefetch function in a sync way? So first the token refreshes and then the Action?
EDIT
We can do the stuff async, the important is the final call to cb(), here is the example
const endpoints = {
{
url: '/some/url',
crud:true,
prefetch:[
({actions, dispatch, getState}, cb) =>{
let mills = new Date().getTime()
const { token, generationTime, accessTokenLife, refreshTokenLife, refreshToken } = localStorage
// Conditions: exixts token, it is expired, refresh token is not expired
if(token && generationTime + accessTokenLife - 500 < mills && generationTime + refreshTokenLife - 500 > mills){
dispatch(actions.token_refresh.get(null, null, (err, data) =>{
if(err){
dispatch(setError(err))
}else{
refreshTokenData(data)
}
cb()
}))
}else{
cb()
}
}
]}}
const api = reduxApi(endpoints)
You may not need to request the token every time you do an async action. In fact, I'd encourage you not to.
You can request the token when you authenticate the user and cache it using web storage. Now instead of sending a network request to retrieve the users token every time you need it, you simply check the browsers cached storage. If the token for the user exists then the user has successfully authenticated. Otherwise, the user has not logged in and you can redirect the user to the authentication page.
Since that was not actually an answer to your problem but rather a different way to solve your problem I will also answer your question in a way that is more inline with the question. You should be able to utilize promise chaining to request the user's token and then once that resolves, do any other action.
I will explain in an abstract way that is not explicity related to redux-api that you should be able to adapt to redux-api specific constructs easy enough.
const actionOne = () => {
actions.post(myJson)
.then(response => actionTwo(response))
.catch(error => console.log(error))
}
An important modification you would need to make is to convert actions.auth_token.post to return a promise. Then you can chain other actions to the resolution of that promise. If you are not familiar with promises MDNs documentation is quite good. For more information on converting a function from callbacks to promises this Stack Overflow answer is quite detailed.

Resources