* Which Category is your question related to? *
API
* What AWS Services are you utilizing? *
AppSync, DynamoDB, Redux Saga
* Provide additional details e.g. code snippets *
I'm trying to make an API call using AWS Amplify's helper methods with Redux Saga.
import { API, graphqlOperation } from 'aws-amplify';
import * as R from 'ramda';
import { call, put } from 'redux-saga/effects';
import { listQuestions } from '../graphql/queries';
import { openSnackbar } from '../snackbar/snackbar-reducer';
import { addQuestions, fetchQuestions as fq } from './question-reducer';
const toAction = R.pipe(
R.path(['data', 'listQuestions', 'items']),
addQuestions
);
function* fetchQuestions() {
try {
const result = yield call(
API.graphql,
graphqlOperation(listQuestions, { limit: 100 })
);
yield put(toAction(result));
} catch (e) {
console.log(e);
yield put(openSnackbar(e.message));
}
}
As you can see, I'm using the API.graphql
and graphqlOperation
helper methods from the JS framework part of AWS Amplify.
But, this always throws the error:
TypeError: Cannot read property '_graphql' of null
at APIClass.graphql (API.js:831)
The given code at APIClass.graphql
looks like this:
APIClass.prototype.graphql = function (_a) {
var paramQuery = _a.query, _b = _a.variables, variables = _b === void 0 ? {} : _b, authMode = _a.authMode;
var query = typeof paramQuery === 'string' ? parser_1.parse(paramQuery) : parser_1.parse(printer_1.print(paramQuery));
var _c = query.definitions.filter(function (def) { return def.kind === 'OperationDefinition'; })[0], operationDef = _c === void 0 ? {} : _c;
var operationType = operationDef.operation;
switch (operationType) {
case 'query':
case 'mutation':
return this._graphql({ query: query, variables: variables, authMode: authMode });
case 'subscription':
return this._graphqlSubscribe({ query: query, variables: variables, authMode: authMode });
}
throw new Error("invalid operation type: " + operationType);
};
Why would this
be null
here? Is there a way to use the GraphQL helper methods from AWS Amplify with Redux Saga?
Just found the solution. You need to supply a this
context to call
.
yield call([API, 'graphql'], graphqlOperation(listQuestions, { limit: 100 }))
Was anyone able to get an auth channel/subscription to keep track of the currentAuthenticatedUser
? Below is how I am trying to do it, but my AWS auth channel is not working. I'm coming from Firebase, so below is an example of a working saga to keep track of the user. Any idea @janhesters?
Firebase Saga (Working):
// Redux Saga: Firebase Auth Channel
export function* firebaseAuthChannelSaga() {
try {
// Auth Channel (Events Emit On Login And Logout)
const authChannel = yield call(reduxSagaFirebase.auth.channel);
while (true) {
const { user } = yield take(authChannel);
// Check If User Exists
if (user) {
// Firebase ID Token
const firebaseIdToken = yield user.getIdTokenResult();
// Redux: Login Success
yield put(loginSuccess(user));
}
else {
// Redux: Logout Success
yield put(logoutSuccess());
// authChannel.close();
}
}
}
catch (error) {
console.log(error);
}
};
AWS Saga (Not Working):
// Redux Saga: AWS Auth Channel
export function* awsAuthChannelSaga() {
try {
console.log('AUTH CHANNEL');
// Auth Channel (Events Emit On Login And Logout)
const currentUser = yield call([Auth, 'currentAuthenticatedUser']);
while (true) {
const { attributes } = yield take(currentUser);
// Check If User Exists
if (attributes) {
console.log('AUTH CHANNEL LOGGED IN');
// Redux: Login Success
yield put(loginSuccess(attributes));
}
else {
console.log('AUTH CHANNEL LOGGED OUT');
// Redux: Logout Success
yield put(logoutSuccess());
}
}
}
catch (error) {
console.log(error);
}
};
Index:
// Root Saga
export default function* rootSaga() {
// AWS Auth Channel
yield fork(awsAuthChannelSaga);
yield all([
// Sagas: Auth
fork(watchLoginSaga),
fork(watchLogoutSaga),
fork(watchResetPasswordSaga),
fork(watchSendVerificationCodeSaga),
]);
};
@jefelewis I just ran into the same issue. Looking at the context link in the post above, the docs for call
indicate the first array index is the context and the second is the _function reference_:
call([context, fn], ...args)
Taking your code here:
// second array index is the function name
const currentUser = yield call([Auth, 'currentAuthenticatedUser']);
and changing it to this worked for me:
// second array index is the function reference
const currentUser = yield call([Auth, Auth.currentAuthenticatedUser]);
Hope that helps.
Most helpful comment
Just found the solution. You need to supply a
this
context tocall
.