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

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);
}
});
});

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(),
})

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.

Async Lambda function returning null on calling DynamoDB

I am new to async functions and promises. I have written a Lambda function which queries a DynamoDB table and returns the result. The code is executing inside the callback success block and I am able to see the response in the log from the console.log(res) line. However the Lambda response is always showing as null, i.e. the response object below is not returned at all. I was able to make this work using a Synchronous Lambda function using a callback to return the data. Can you please suggest what I may be doing incorrectly.
const doc = require('dynamodb-doc');
var dynamodbclient;
const tablename = process.env.TABLE_NAME;
exports.handler = async(event) => {
if (!dynamodbclient) {
dynamodbclient = new doc.DynamoDB();
}
let id = event.params.id;
let queryparams = {
TableName: 'table-name',
Key: { id: id }
};[![enter image description here][1]][1]
var getItemsCallback = (err, res) => {
console.log('inside');
if (err) {
}
else {
console.log('success');
console.log(res);
const response = {
statusCode: 200,
body: JSON.stringify('Hello from Lambda!'),
};
return response;
}
};
var item = await dynamodbclient.getItem(queryparams, getItemsCallback).promise();
};
Your callback is still executing after the promise resolves, so the lambda will terminate and your callback will not finish.
Try:
try {
const item = await dynamodbclient.getItem(queryparams).promise();
} catch (err) {}
console.log('success');
console.log(item);
const response = {
statusCode: 200,
body: JSON.stringify('Hello from Lambda!'),
};
return response;

How to use async and await in gmail read message API

I tried using async/await instead of the callback for reading the Gmail
Here is the code snippet
const {google} = require('googleapis');
async function getRecentMessageBody(auth) {
const gmail = google.gmail({version: 'v1', auth});
try{
const messageId = await gmail.users.messages.list({
userId: 'me',
labelIds: 'INBOX',
maxResults: 1
});
const message = await gmail.users.messages.get({
userId: 'me',
id: messageId.data.messages[0].id,
format : 'full'
});
const value = base64url.decode(message.data.payload.body.data);
console.log(messageId);
//return value ;
}
catch(error) {
console.log('Error occurs while reading mail :'+ error);
throw error;
}
}
But the messageId is undefined
whereas if i use
gmail.users.labels.list({
userId: 'me',
}, (err, res) => {
if (err) return console.log('The API returned an error: ' + err);
const labels = res.data.labels;
if (labels.length) {
console.log('Labels:');
labels.forEach((label) => {
console.log(`- ${label.name}`);
});
} else {
console.log('No labels found.');
}
});
how to fix the issue??
use promisfy to convert callback to promises

How to handle Google OAuth flow via redux-saga

I am trying to implement Google OAuth 2 with with redux saga.
I have a watcher in my saga listening for GOOGLE_AUTH action which then executes googleLogin
function *watchGoogleAuth() {
yield *takeLatest(GOOGLE_AUTH, googleLogin)
}
function *googleLogin() {
const id_token = yield call(GoogleSignIn);
console.log(id_token);
const response = yield call(HttpHelper, 'google_token', 'POST', id_token, null);
console.log(response);
}
The implementation for GoogleSignIn is in apis.js
export function GoogleSignIn() {
const GoogleAuth = window.gapi.auth2.getAuthInstance();
GoogleAuth.signIn({scope: 'profile email'})
.then(
(res) => {
const GoogleUser = GoogleAuth.currentUser.get();
return {
id_token: GoogleUser.getAuthResponse().id_token
};
},
(err) => {
console.log(err)
}
)
}
But saga doesn't seem to wait for the GoogleSignIn to complete. As soon as OAuth consent screen pops up, saga proceeds executing the console.log without waiting for google signin promise to return actual data.
Is there any better way to handle this situation? Thanks!
To expand on #HenrikR's answer, the generator will not wait unless it receives a promise.
export const GoogleSignIn = () => {
const GoogleAuth = window.gapi.auth2.getAuthInstance();
return new Promise((resolve, reject) => {
GoogleAuth.signIn({scope: 'profile email'})
.then(
(res) => {
const GoogleUser = GoogleAuth.currentUser.get();
resolve(GoogleUser.getAuthResponse().id_token);
},
(err) => {
reject(err);
}
);
});
};
Accordingly, you should wrap the yield statement in a try/catch. Simplified and somewhat lazy:
function *googleLogin() {
try {
const id_token = yield call(GoogleSignIn);
if (id_token) { /* Possibly with more checks and validations */
console.log(id_token);
const response = yield call(HttpHelper, 'google_token', 'POST', id_token, null);
console.log(response);
}
} catch (e) {
console.log(e);
}
}

Resources