Adding multiple API calls to a map in reactjs using axios - reactjs

I need my API call to pull NFT data from moralis and add it to a map so it can later be rendered.
This all works fine, however the limit per call on moralis is 100 lines. I have added a second API call using cursor pagination. Both API calls work individually but when I try to add both to the map it just renders the most recent one. Is there a way to show everything in the collection? Thanks in advance!!
Here is the code I currently have to call the API:
async function callApi() {
var provider = await web3Modal.connect();
web3 = new Web3(provider);
await provider.send('eth_requestAccounts');
var accounts = await web3.eth.getAccounts();
account = accounts[0];
vaultcontract = new web3.eth.Contract(VAULTABI, STAKINGCONTRACT);
let config = { 'X-API-Key': moralisapikey, 'accept': 'application/json', cursor: '' };
const nfts0 = await axios.get((moralisapi + `nft/${NFTCONTRACT}/owners?chain=polygon&format=decimal&limit=100`), { headers: config })
.then(output => {
const { result } = output.data
return result;
})
const nfts1 = await axios.get((moralisapi + `nft/${NFTCONTRACT}/owners?chain=polygon&format=decimal&limit=100`), { headers: config })
.then(output => {
const { result } = output.data
return result;
})
const nfts = (nfts0, nfts1)
const apicall = await Promise.all(nfts.map(async i => {
let item = {
tokenId: i.token_id,
holder: i.owner_of,
wallet: account,
}
return item
}))
const stakednfts = await vaultcontract.methods.tokensOfOwner(account).call()
.then(id => {
return id;
})
const nftstk = await Promise.all(stakednfts.map(async i => {
let stkid = {
tokenId: i,
}
return stkid
}))
getNfts(apicall)
getStk(nftstk)
console.log(apicall);
setLoadingState('loaded')
}

Related

State Not Finished Setting before being used in useEffect

I am hosting a react app in aws amplify using the aws-serverless version of express as the REST API, which sits inside of a lambda function. A big problem that I am facing is that asynchronous jobs in aws-serverless express cause the lambda function to complete before the promises resolve. Leaving me with no data and no error handling. This caused me to bring a lot of the asynchronous work to the front end of the application.
The problem here is that I need to bring a large amount of data into state. Right now, I am using a delay workaround (shown below) but instead need a programatic way to make sure state is finished updating before being used in the second useEffect hook (dependent on odds & failedTries props) instead of using the delay functionality.
Any help would be greatly appreciated.
const App = ({ signOut }) => {
const [odds, setOdds] = useState([]);
const [updateTime,setUpdateTime] = useState(0);
const [failedTries,setFailedTries] = useState(0);
useEffect(() => {
const setNflOdds = async () => {
let response = await updateNflOdds();
let data = response;
setOdds(data);
};
setNflOdds();
setUpdateTime(1);
const interval = setInterval(() => {
setNflOdds();
setUpdateTime(updateTime => updateTime +1);
}, 100000);
return () => clearInterval(interval);
}, []);
useEffect(() => {
const s3Push = (() => {
if(!odds.length) {
setFailedTries(failedTries => failedTries + 1);
} else {
const delay = ms => new Promise(res => setTimeout(res, ms));
const nflOddsRefDelay = async() => {
*//This is the current workaround, wait ten seconds before pushing odds state up to the s3 bucket*
await delay(10000);
oddsS3Helper(odds);
};
nflOddsRefDelay()
}
});
s3Push();
}, [odds, failedTries]);
With the above indicated delay workaround this works for my use case (13k records inside of the array) but the data size is highly variable and I want to figure out a way that no matter the data size it brings the entire call up to the s3 bucket.
below is the content of the functions being called in the useEffect hook
const pushToS3 = async ( file, key ) => {
const creds = await Auth.currentCredentials()
const REGION = {region};
const s3Client = new S3Client({
credentials: Auth.essentialCredentials(creds),
region: REGION
});
const params = {
Bucket: {s3 bucket name}
Key: key,
Body: file,
};
s3Client.send(new PutObjectCommand(params));
console.log("file is sent");
};
const oddsS3Helper = (async (odds) => {
console.log("inside s3 helper: ",odds);
let csv = '';
let headers = Object.keys(odds[0]).join(',');
let values = odds.map(odd => Object.values(odd).join(',')).join('\n');
csv += headers + '\n' + values;
const buffedFile = csv;
const key = 'nflprops.csv'
const delay = ms => new Promise(res => setTimeout(res, ms));
const propRefDelay = async() => {
await delay(5000);
await postNflOdds();
};
pushToS3( buffedFile, key );
await propRefDelay();
});
async function getNflGames() {
const apiName = {name of serverless API inside of lambda};
const path = {path name};
const init = {
headers: {} // OPTIONAL
};
const data = await API.get(apiName, path, init);
return data;
};
async function getNflOdds(gameId) {
const apiName = {name of serverless API inside of lambda};
const path = {path name};
const init = {
headers: {}, // OPTIONAL
body: { gameId }
};
const data = await API.post(apiName, path, init);
return data;
};
async function updateNflOdds() {
const ojNflGames = await getNflGames();
const nflGameProps = [];
const nflOddsPush = ( async () => {
try {
await ojNflGames.data.map( async (game) => {
const ojNflOdds = await getNflOdds(game.id)
await ojNflOdds.data[0].odds.map((line) => {
nflGameProps.push(
{
gameId: game.id,
oddsId: line.id,
sports_book_name: line.sports_book_name,
name: line.name,
price: line.price,
checked_date: line.checked_date,
bet_points: line.bet_points,
is_main: line.is_main,
is_live: line.is_live,
market_name: line.market_name,
home_rotation_number: line.home_rotation_number,
away_rotation_number: line.away_rotation_number,
deep_link_url: line.deep_link_url,
player_id: line.player_id,
}
);
});
});
} catch (err) {
console.log("there was an error", err);
}
});
try {
await nflOddsPush();
} catch(err) {
console.log("odds push errored: ", err);
}
console.log("inside of updateNflOdds function: ",nflGameProps);
return nflGameProps;
};

MS Graph API issue with React

I'm working on a React project.
I'm able to sign in in the graph API, also able to get the user's contacts, but, not able to get his calendar events.
the config file:
export const msalConfig = {
auth: {
clientId: "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
authority: "https://login.microsoftonline.com/common",
redirectUri: "http://localhost:4200",
},
cache: {
cacheLocation: "sessionStorage", // This configures where your cache will be stored
storeAuthStateInCookie: true, // Set this to "true" if you are having issues on IE11 or Edge
}
};
// Add scopes here for ID token to be used at Microsoft identity platform endpoints.
export const loginRequest = {
scopes: ["Calendars.ReadWrite", "Contacts.Read"]
};
// Add the endpoints here for Microsoft Graph API services you'd like to use.
export const graphConfig = {
graphMeEndpoint: "https://graph.microsoft.com/v1.0/me",
graphCalendarsEndpoint: "https://graph.microsoft.com/v1.0/me/events",
graphContactsEndpoint: "https://graph.microsoft.com/v1.0/me/contacts",
};
1/ The working part
the importContact.jsx file:
...
import { loginRequest, graphConfig } from '../authConfig.jsx';
import { useMsal } from "#azure/msal-react";
const ImportContacts = (props) => {
const { instance, accounts, inProgress } = useMsal();
const [accessToken, setAccessToken] = useState(null);
const [graphData, setGraphData] = useState(null);
const getMicrosoftContacts = () => {
const request = {
...loginRequest,
account: accounts[0]
};
var contacts= [];
// Silently acquires an access token which is then attached to a request for Microsoft Graph data
instance.acquireTokenSilent(request).then((response) => {
console.log('acquireTokenSilent')
setAccessToken(response.accessToken);
callMsGraph(response.accessToken).then(
response => {
setGraphData(response);
console.log(response)
for (const item of response.value){
contacts.push({
provider: 'Microsoft',
id: item.id,
email: item.emailAddresses[0].address,
firstName: item.givenName,
lastName: item.surname,
name: item.displayName,
label:item.displayName + " (" + item.emailAddresses[0].address + ")" }
)
}
setItems(contacts);
}
);
}).catch((e) => {
instance.acquireTokenPopup(request).then((response) => {
setAccessToken(response.accessToken);
callMsGraph(response.accessToken).then(
response => {
setGraphData(response);
for (const item of response.value){
contacts.push({
provider: 'Microsoft',
id: item.id,
email: item.emailAddresses[0].address,
firstName: item.givenName,
lastName: item.surname,
name: item.displayName,
label:item.displayName }
)
}
setItems(contacts);
}
);
});
});
}
async function callMsGraph(accessToken) {
const headers = new Headers();
const bearer = `Bearer ${accessToken}`;
headers.append("Authorization", bearer);
const options = {
method: "GET",
headers: headers
};
return fetch(graphConfig.graphContactsEndpoint, options)
.then(response => response.json())
.catch(error => console.log(error));
}
...
}
2/ The non working part in events.jsx file:
...
import { loginRequest, graphConfig } from '../authConfig.jsx';
import { useMsal } from "#azure/msal-react";
class Events extends Component {
constructor(props) {
super(props);
this.getMicrosoftEvents = this.getMicrosoftEvents.bind(this);
}
componentDidMount(){
var date = new Date();
var firstDay = new Date(date.getFullYear(), date.getMonth(), 1);
var lastDay = new Date(date.getFullYear(), date.getMonth() + 1, 0);
this.getMicrosoftEvents(firstDay, lastDay);
}
getMicrosoftEvents(start, end) {
console.log('log displayed in console')
const { instance, accounts, inProgress } = useMsal();
const [accessToken, setAccessToken] = useState(null);
const [graphData, setGraphData] = useState(null);
console.log('log not displayed in console')
const request = {
...loginRequest,
account: accounts[0]
};
// Silently acquires an access token which is then attached to a request for Microsoft Graph data
instance.acquireTokenSilent(request).then((response) => {
console.log('acquireTokenSilent')
setAccessToken(response.accessToken);
callMsGraph(response.accessToken, start, end).then(
response => {
console.log('microsoft response ' + response)
}
);
}).catch((e) => {
console.log('microsoft response error ' + e)
instance.acquireTokenPopup(request).then((response) => {
setAccessToken(response.accessToken);
callMsGraph(response.accessToken, start, end).then(
response => {
console.log('microsoft response ' + response)
}
);
});
});
async function callMsGraph(accessToken, start, end) {
console.log('callMsGraph ')
const headers = new Headers();
const bearer = `Bearer ${accessToken}`;
headers.append("Authorization", bearer);
console.log('Authorization ' + bearer)
const options = {
method: "GET",
headers: headers
};
return fetch(graphConfig.graphCalendarsEndpoint
+ '?startDateTime='
+ start
+ '&endDateTime='
+ end,
options)
.then(response => {
console.log('microsoft response ' + response.json())
response.json();
})
.catch(error => console.log(error));
}
}
I'm not getting any error, the api call is not made, the difference between the two calls is one is made after a button click, and the other on load.
Adding logs showed me that the problem could be in this line as the logs are not displayed after it:
const { instance, accounts, inProgress } = useMsal();
What am I doing wrong?
In events.jsx Events component is a class component and you are calling useMsal() and useState() hooks in getMicrosoftEvents. That will not work because hooks can only be called in function components.
You need to make Events component functional like ImportContacts.
Instead of
class Events extends Component {
...
Do this
const Events= (props) => {
const { instance, accounts, inProgress } = useMsal();
const [accessToken, setAccessToken] = useState(null);
const [graphData, setGraphData] = useState(null);
...

What do I put in my return if I want to return the response from an api call react?

I needed to add headers to my api call. I tried doing this many different ways to no avail. This is my original api call without the header:
export default async function FetchPageMarkdown(page: string): Promise<string> {
const baseUrl = getBackendUrl();
let response = await fetch(`${baseUrl}/api/pagemarkdown/${page}`);
let text = await response.text();
return text
}
This is how I am trying to add the header:
const FetchPageMarkdown = (page: string): Promise<string> => {
const { getAccessTokenSilently } = useAuth0();
const callSecureApi = async () => {
const token = await getAccessTokenSilently();
const baseUrl = getBackendUrl();
const response = await fetch(
`${baseUrl}/api/pagemarkdown/${page}`,
{
headers: {
Authorization: `Bearer ${token}`,
},
}
);
const text = await response.text();
return text;
}
};
export default FetchPageMarkdown;
Without having a return I get a function whose declared type is neither 'void' nore 'any' must return a value. I want to return the text coming from the api call which is markdown. If I put the return outside the callSecureApi function it cannot find text.
Have you tried calling and returning the result of the asynchronous function, i.e. return callSecureApi();?
Since useAuth0 is a React hook it can't be called from functions (breaks rules of hooks), but its getAccessTokenSilently function can be passed around.
const fetchPageMarkdown = (getAccessTokenSilently: () => string, page: string): Promise<string> => {
const callSecureApi = async () => {
const token = await getAccessTokenSilently();
const baseUrl = getBackendUrl();
const response = await fetch(
`${baseUrl}/api/pagemarkdown/${page}`,
{
headers: {
Authorization: `Bearer ${token}`,
},
}
);
const text = await response.text();
return text;
}
return callSecureApi(); // invoke and return Promise
};
Usage:
const { getAccessTokenSilently } = useAuth0();
fetchPageMarkdown(getAccessTokenSilently, page)
.then(text => {
// handle returned text
});

How to fetch API data from Axios inside the getServerSideProps function in NextJS?

I'm building an App with Next.js, and I need to connect to specific API routes (set up with API Platform) and populate pages with the route's responses.
The API is working fine, but no matter how I try to implement my Axios call inside the getServerSideProps, I always get the same error, ECONNREFUSED, from my Node stack.
I tried to get the data from useEffect() and it's working fine, but I would like to know if there's a way to call it directly in getServerSideProps.
I'm using a Node container for Docker, and the routes are authenticated through a JWT Token (stored in the session and the client cookies for the server-side connection)
Here are is my code:
pages/accounts.js:
export async function getServerSideProps(context) {
const cookies = new Cookies(context.req.headers.cookie)
const adminToken = cookies.get('jwtToken')
const res = await getAllAccounts(adminToken)
return {
props: {
testdata: ''
},
}
}
lib/accounts.js:
import service from '../service'
export const getAllAccounts = async (adminToken) => {
const res = service({ jwtToken : adminToken }).get(`/accounts`).then((response) => {
}).catch((error) => {
console.dir(error)
})
}
HTTP wrapper:
import axios from 'axios';
import jwt_decode from "jwt-decode";
import mockAdapter from 'axios-mock-adapter';
const service = ({ jwtToken = null, store = null, mockURL = null, mockResponse = null, multipart = false } = {}) => {
const options = {};
options.baseURL = process.env.NEXT_PUBLIC_API_URL + '/api';
if(multipart === true) {
options.headers = {
'Content-Type': 'multipart/form-data'
}
} else {
options.headers = {
'Content-Type': 'application/ld+json',
accept: 'application/ld+json'
}
}
const instance = axios.create(options);
instance.interceptors.response.use(response => {
return response;
}, error => {
return Promise.reject(error);
})
if (mockURL !== null && mockResponse !== null) {
let mock = new mockAdapter(instance);
mock.onAny(mockURL).reply(200, mockResponse)
}
return instance;
};
export default service;
Through the error dump in the node stack, I managed to see that the request headers are correct, and the JWT correctly passed through.
Do not use Axios. Just use fetch().
Next.js polyfills fetch() by default on both the client and server, so you can just use it:
In addition to fetch() on the client-side, Next.js polyfills fetch() in the Node.js environment. You can use fetch() in your server code (such as getStaticProps/getServerSideProps) without using polyfills such as isomorphic-unfetch or node-fetch.
Source.
getServerSideProps works well with axios if we return response.data
export const getServerSideProps: GetStaticProps = async ({ params }) => {
const { brandName } = params as IParams;
const brandData = await $host.get(`api/brand/${brandName}`).then(response => response.data);
return {
props: {
brand: brandData,
},
};
};
Your problem is that your async method does not return a promise.
import service from '../service'
export const getAllAccounts = async (adminToken) => {
const res = service({ jwtToken : adminToken }).get(`/accounts`);
return res;
}
In my NextJS begining I followed this tutorial , and I changed fetch to axios in this way:
export const getStaticPaths = async () => {
const res = await fetch('https://jsonplaceholder.typicode.com/users');
const data = await res.json();
const paths = data.map((ninja) => {
return {
params: { id: ninja.id.toString() },
};
});
return {
paths,
fallback: false,
};
};
export const getStaticProps = async (context) => {
const id = context.params.id;
const res = await fetch(`https://jsonplaceholder.typicode.com/users/${id}`);
const data = await res.json();
return {
props: { ninja: data },
};
};
I applied the change using useEffect()
useEffect(() => {
// const data = await fetch(`https://jsonplaceholder.typicode.com/users/${id}`);
// const res = await data.json();
// setninja(res);
const fetchData = async () => {
const result = await axios(`https://jsonplaceholder.typicode.com/users/${id}`);
setninja(result.data);
};
fetchData();
console.log(data);
}, []);
I hope this info will be useful for you.
I Used Axios in getServerSideProps without any problems.
export const getServerSideProps: GetServerSideProps = async({
params,
res
}) => {
try {
const response = await axios.get(`/api/test`);
return {
props: {
data: response.data
},
}
} catch {
res.statusCode = 404;
return {
props: {}
};
}
};

React Native - iOS subscription receipt verification (firebase)

currently I am working on a app but struggling to find since last two weeks the following:
I have react native iOS app with RN-iap for subscription.. and would like to implement receipt verification via cloud function at firebase.
I found a similar solution but its with SWIFT: https://www.loopwerk.io/articles/2020/storekit-webhooks-firestore/
can anybody please help me convert the code (swift below) into React Native ? really appreciate
or if any suitable example or lines please.
(I am using React native firebase).
I can able to fetch receipt and save in Firestore collection. Thanks in advance.
below are the codes:
FRONT END CALLING Cloud function
import Firebase
import FirebaseFunctions
import Foundation
final class CloudFunction {
private lazy var functions = Functions.functions()
func validateReceipt(receipt: String, completionHandler: #escaping () -> Void) {
let parameters = ["receipt": receipt]
functions.httpsCallable("validateReceipt").call(parameters) { _, error in
if let error = error {
print(error)
}
completionHandler()
}
}
}
Cloud Function for above:
const functions = require('firebase-functions');
const admin = require('firebase-admin');
const fetch = require('node-fetch');
const db = admin.firestore();
const runtimeOpts = {
memory: '1GB',
};
function validateAndStoreReceipt(url, options, userSnapshot) {
return fetch(url, options).then(result => {
return result.json();
}).then(data => {
if (data.status === 21007) {
// Retry with sandbox URL
return validateAndStoreReceipt('https://sandbox.itunes.apple.com/verifyReceipt', options, userSnapshot);
}
// Process the result
if (data.status !== 0) {
return false;
}
const latestReceiptInfo = data.latest_receipt_info[0];
const expireDate = +latestReceiptInfo.expires_date_ms;
const isSubscribed = expireDate > Date.now();
const status = {
isSubscribed: isSubscribed,
expireDate: expireDate,
};
const appleSubscription = {
receipt: data.latest_receipt,
productId: latestReceiptInfo.product_id,
originalTransactionId: latestReceiptInfo.original_transaction_id
};
// Update the user document!
return userSnapshot.ref.update({status: status, appleSubscription: appleSubscription});
});
}
exports.validateReceipt = functions.runWith(runtimeOpts).https.onCall(async (data, context) => {
if (!context.auth) {
throw new functions.https.HttpsError('permission-denied', 'The function must be called while authenticated.');
}
if (!data.receipt) {
throw new functions.https.HttpsError('permission-denied', 'receipt is required');
}
// First we fetch the user
const userSnapshot = await db.collection('users').doc(context.auth.uid).get();
if (!userSnapshot.exists) {
throw new functions.https.HttpsError('not-found', 'No user document found.');
}
// Now we fetch the receipt from Apple
let body = {
'receipt-data': data.receipt,
'password': 'MY_SECRET_PASSWORD',
'exclude-old-transactions': true
};
const options = {
method: 'post',
body: JSON.stringify(body),
headers: {'Content-Type': 'application/json'},
};
return validateAndStoreReceipt('https://buy.itunes.apple.com/verifyReceipt', options, userSnapshot);
});
continuation another cloud function:
const functions = require('firebase-functions');
const admin = require('firebase-admin');
const db = admin.firestore();
const runtimeOpts = {
memory: '1GB',
};
exports.appleWebhook = functions.runWith(runtimeOpts).https.onRequest(async (req, res) => {
// Only allow POST requests
if (req.method !== 'POST') {
return res.status(403).send('Forbidden');
}
// Check for correct password
if (req.body.password !== 'MY_SECRET_PASSWORD') {
return res.status(403).send('Forbidden');
}
const receipt = req.body.unified_receipt.latest_receipt_info[0];
// Find the user with this stored transaction id
const userQuerySnapshot = await db.collection('users')
.where('appleSubscription.originalTransactionId', '==', receipt.original_transaction_id)
.limit(1)
.get();
if (userQuerySnapshot.empty) {
throw new functions.https.HttpsError('not-found', 'No user found');
}
const expireDate = +receipt.expires_date_ms;
const isSubscribed = expireDate > Date.now();
const status = {
isSubscribed: isSubscribed,
expireDate: expireDate,
};
const appleSubscription = {
receipt: req.body.unified_receipt.latest_receipt,
productId: receipt.product_id,
originalTransactionId: receipt.original_transaction_id,
};
// Update the user
return userQuerySnapshot.docs[0].ref.update({ status: status, appleSubscription: appleSubscription }).then(function() {
return res.sendStatus(200);
});
});

Resources