use async/await instead of (.then) - react-redux

I am trying to replace .then with async/await
here is my code
export const loginUser = (userData) => async dispatch => {
try {
await axios.post('/api/users/login', userData);
// Save to localStorage
const {token} = res.data;
// Save token to local storage
localStorage.setItem('jwtToken', token);
// Set token to Auth header
setAuthToken(token);
// Decode to get user data
const decoded = jwt_decode(token);
// set current user
dispatch(setCurrentUser(decoded));
} catch (err) {
dispatch({
type: GET_ERRORS,
payload: err.response.data
})
}
};
and then this is the error
Unhandled Rejection (TypeError): Cannot read property 'data' of
undefined ▶ 6 stack frames were collapsed.

Related

Apollo Client GraphQL: When getting FORBIDDEN error, automatically get new JWT AccessToken and RefreshToken. How does the logic work?

In the following code, you can see that I am creating an errorLink. It makes use of an observable, a subscriber and then it uses this forward() function.
Can someone explain to me what's exactly happening here. I am bit familiar with observables, but I cannot understand what's going on here.
When creating the observable, where does the observer argument come from?
I would love to dive a bit deeper.
Also, why is bind used, when creating the subscriber?
const errorLink = onError(
({ graphQLErrors, networkError, operation, forward }) => {
if (graphQLErrors) {
for (let err of graphQLErrors) {
switch (err.extensions.code) {
case "FORBIDDEN":
console.log("errs!")
// ignore 401 error for a refresh request
if (operation.operationName === "RehydrateTokens") return
const observable = new Observable<FetchResult<Record<string, any>>>(
(observer) => {
console.log(observer)
// used an annonymous function for using an async function
;(async () => {
try {
console.log("yop bin hier")
const accessToken = await refreshToken()
console.log("AT!", accessToken)
if (!accessToken) {
throw new GraphQLError("Empty AccessToken")
}
// Retry the failed request
const subscriber = {
next: observer.next.bind(observer),
error: observer.error.bind(observer),
complete: observer.complete.bind(observer),
}
forward(operation).subscribe(subscriber)
} catch (err) {
observer.error(err)
}
})()
}
)
return observable
}
}
}
if (networkError) console.log(`[Network error]: ${networkError}`)
}
)
Just so that you are understanding the context.
Iam combining mutliple apollo links.
const httpLink = createHttpLink({
uri: "http://localhost:3000/graphql",
})
// Returns accesstoken if opoeration is not a refresh token request
function returnTokenDependingOnOperation(operation: GraphQLRequest) {
if (isRefreshRequest(operation)) {
return localStorage.getItem("refreshToken")
} else return localStorage.getItem("accessToken")
}
const authLink = setContext((operation, { headers }) => {
let token = returnTokenDependingOnOperation(operation)
console.log("tk!!!", token)
return {
headers: {
...headers,
authorization: token ? `Bearer ${token}` : "",
},
}
})
const client = new ApolloClient({
link: ApolloLink.from([errorLink, authLink, httpLink]),
cache: new InMemoryCache(),
})

How to get error from backend with axios?

I'm trying to display an error I recieve in my backend to the user in my JSX frontend file.
This is the initial call from frontend
dispatch(createGoal({ values }))
Goalslice, directly called from JSX:
export const createGoal = createAsyncThunk(
'goals/create',
async (goalData, thunkAPI) => {
try {
const token = thunkAPI.getState().auth.user.token
return await goalService.createGoal(goalData, token)
} catch (error) {
const message =
(error.response &&
error.response.data &&
error.response.data.message) ||
error.message ||
error.toString()
return thunkAPI.rejectWithValue(message)
}
}
)
Goalservice, directly called from goalslice:
const createGoal = async (goalData, token) => {
const config = {
headers: {
Authorization: `Bearer ${token}`,
},
}
const response = await axios.post(API_URL, goalData, config)
return response.data
}
Goalcontroller, my backend:
const setGoal = asyncHandler(async (req, res) => {
const goals = await Goal.find({ user: req.user.id })
var count = Object.keys(goals).length
if(count >2){
res.status(400)
throw new Error('Maximum of 3 trackers per user')
}
if (!req.body.values) { //if this isnt there. check if the body is there.
res.status(400) //This is an error
throw new Error('Please add a date field') //this is express error handler
}
console.log(req.body.values.dates)
const goal = await Goal.create({
values: req.body.values.dates, //get from request body
permit: req.body.values.permits,
numpermit: req.body.values.num,
user: req.user.id,
})
res.status(200).json(goal)
})
I want to display this error:
throw new Error('Maximum of 3 trackers per user')
I tried a try/catch method, but I'm very new to this and I feel like i'm missing a very key point in how it all fits together.
This is my custom error handler if it helps:
const errorHandler = (err, req, res, next) => { //overwrite express error handler, next to handle any new req
const statusCode = res.statusCode ? res.statusCode : 500 //500 is server error. conditional
res.status(statusCode)
res.json({
message: err.message,
stack: process.env.NODE_ENV === 'production' ? null : err.stack, //gives additional info if in development mode : is else
})
}
module.exports = { //export for others to use
errorHandler,
}

401 - unauthorized call to Twitch Api from nextjs

I have this code:
const getToken = async () => {
return Axios.post(
`https://id.twitch.tv/oauth2/token?client_id=${process.env.TWITCH_ID}&client_secret=${process.env.TWITCH_SECRET}&grant_type=client_credentials`
).then((res) => res.data["access_token"]);
};
const getId = async (accessToken, session) => {
const response = await Axios.get(
`https://api.twitch.tv/helix/users?login=${session.user.name}`,
{
Authorization: `Bearer ${accessToken}`,
"Client-Id": process.env.TWITCH_ID,
}
);
return response.data.id;
};
export async function getServerSideProps(context) {
const session = await getSession(context);
if (session) {
const accessToken = await getToken();
console.log(accessToken);
const id = await getId(accessToken, session);
console.log(id);
}
return {
props: {}, // will be passed to the page component as props
};
}
This is Next.js function that will do this on every request.
I am using Next.js, next-auth for authentication.
Everything should work fine, even on line console.log(accessToken) I get the expected output. But in function getId it says 401 - unauthorized.
I am calling Twitch api.

how to set up redux with NextJs and allow dispatching of actions

Im trying to set up redux for my NextJS React App and I'm having some complications when dispatching this action through the indicated link. An error of 'Network Error' is displayed on LIST_FAIL. Any well available resources or advice would be appreciated. Thanks.
import axios from 'axios';
import {
//NOte that these are actions which will be dispatched or fired in the action y using dispatch()
LIST_REQUEST,
LIST_SUCCESS,
LIST_FAIL,
} from '../constants/customerConstants';
export const listCusts = () => async (dispatch, getState) => {
try {
//our first request to the backend to get the token
dispatch({
type:LIST_REQUEST,
});
const { data } = await axios.get('https://byronochara.tech/gassystem/api/v1/customers');
console.log(data);
const result = data.results;
// console.log('Results now an Array', result); //This is now an array to be looped in the list screen
dispatch({
type: LIST_SUCCESS,
payload: result,
});
} catch (error) {
dispatch({
type: LIST_FAIL,
payload:
error.response && error.response.data.message
? error.response.data.message
: error.message,
});
}
};

Apollo Server: How can I send a response based on a callback?

I am currently trying to validate iOS receipts for in app purchases using this package: https://github.com/Wizcorp/node-iap
This is my incomplete resolver:
export default {
Query: {
isSubscribed: combineResolvers(
isAuthenticated,
async (parent, args, { models, currentUser }) => {
const subscription = await models.Subscription.find({ user: currentUser.id });
const payment = {
...
};
iap.verifyPayment(subscription.platform, payment, (error, response) => {
/* How do I return a response here if it is async and I don't have the response object? */
});
}
),
},
};
How do I return a response here if it is async and I don't have the response object? Normally, I'm just used to returning whatever the model returns. However, this time I'm using node-iap and it's callback based.
You can use a Promise:
const response = await new Promise((resolve, reject) => {
iap.verifyPayment(subscription.platform, payment, (error, response) => {
if(error){
reject(error);
}else{
resolve(response);
}
});
});

Resources