I'm fairly new to graphql/apollo setup, and am stuck on the following issue:
My setup looks like this roughly:
Resolvers:
export const resolvers: Resolvers = {
Query: {
getUser: withApiAuthRequired(getUser)
}
};
async function getUser(req: any, res: any) {
try {
const { accessToken } = await getAccessToken(req, res);
console.log(accessToken);
} catch (error) {
console.error(error);
res.status(error.status || 500).end(error.message);
}
}
Client caller:
const data = await client.query({
query: gql`
query UsersQuery {
getUser
}
`
});
console.log(data);
The error I get:
Uncaught (in promise) Error: Request is not available
at new ApolloError (index.js?f0e4:29:1)
at eval (QueryManager.js?2692:596:1)
at both (asyncMap.js?bd9c:16:46)
at eval (asyncMap.js?bd9c:9:57)
at new Promise (<anonymous>)
at Object.then (asyncMap.js?bd9c:9:1)
at Object.eval [as next] (asyncMap.js?bd9c:17:1)
at notifySubscription (module.js?9653:132:1)
at onNotify (module.js?9653:176:1)
at SubscriptionObserver.next (module.js?9653:225:1)
at eval (iteration.js?aad9:4:50)
at Array.forEach (<anonymous>)
at iterateObserversSafely (iteration.js?aad9:4:1)
at Object.next (Concast.js?eb39:25:43)
at notifySubscription (module.js?9653:132:1)
at onNotify (module.js?9653:176:1)
at SubscriptionObserver.next (module.js?9653:225:1)
at eval (createHttpLink.js?2d67:103:1)
Thank you so much for the guidance!
try this one:
const data = await client.query({
query: gql `
query {
getUser
}
`
});
console.log(data);
I believe the issue is that I was trying to use withApiAuthRequired inside Resolvers. The argument to Resolvers needs to be an unwrapped function to work. I ended up just skipping the withApiAuthRequired wrapper and using getSession instead.
Related
I'm currently working on the sign in component portion of my app. It requires the user to sign in with their email and password. It has firebase incoporated on the back end. I've been using redux toolkit for a bulk of the app. However, I'm having trouble with createAction and trying to pass the payload in sucessfully. I also wanted to note that i'm doing the async actions via sagas. Could anyone tell me what I'm doing wrong? I provided the error in the console log:
export const emailSignInStart = createAction(
"user/EmailSignInStart",
({ email, password }) => ({
payload: {
email,
password
}
})
);
export function* getSnapShotFromUserAuth(userAuth, additionalDetails) {
try {
const userSnapshot = yield call(
createUserDocumentFromAuth,
userAuth,
additionalDetails
);
yield put(signInSuccess({ id: userSnapshot.id, ...userSnapshot.data() }));
} catch (error) {
yield put(signInFailure(error));
}
}
export function* EmailSignIn({ payload: { email, password } }) {
try {
const { user } = yield call(
signInAuthUserWithEmailAndPassword,
email,
password
);
yield call(getSnapShotFromUserAuth, user);
} catch (error) {
yield put(signInFailure(error));
}
}
Result in console:
payload
:
TypeError: Cannot read properties of undefined (reading 'user') at eval (https://pyluef.csb.app/src/sagas/user/user.saga.js:67:29) at Generator.next (<anonymous>) at next (https://pyluef.csb.app/node_modules/#redux-saga/core/dist/redux-saga-core.dev.cjs.js:1161:27) at currCb (https://pyluef.csb.app/node_modules/#redux-saga/core/dist/redux-saga-core.dev.cjs.js:1255:7)
message
:
"Cannot read properties of undefined (reading 'user')"
stack
:
"TypeError: Cannot read properties of undefined (reading 'user')\n at eval (https://pyluef.csb.app/src/sagas/user/user.saga.js:67:29)\n at Generator.next (<anonymous>)\n at next (https://pyluef.csb.app/node_modules/#redux-saga/core/dist/redux-saga-core.dev.cjs.js:1161:27)\n at currCb (https://pyluef.csb.app/node_modules/#redux-saga/core/dist/redux-saga-core.dev.cjs.js:1255:7)"
[[Prototype]]
:
Error
type
:
"user/signInFailure"
##redux-saga/SAGA_ACTION
:
true
The code I used without using Redux toolkit. It worked this way:
export const USER_ACTION_TYPES = {
EMAIL_SIGN_IN_START: "user/EMAIL_SIGN_IN_START"
};
export const createAction = (type, payload) => ({ type, payload });
export const emailSignInStart = (email, password) =>
createAction(USER_ACTION_TYPES.EMAIL_SIGN_IN_START, { email, password });
I am using NextJS and created three layers that separate the logic.
The purpose is to minimise the error handling to the getServerSideProps section. I want to get all the lists from the database.
In the first layer, in the API route I created a folder called get-all-lists and a file [userId].js. The get request will be 'http://localhost:3000/api/get-all-lists/iudga937gr8'. Bellow there is the api route that get all the lists with the help of Prsima. It is working perfectly
import prisma from '../../../lib/prisma'
export default async function handler(req, res) {
const { userId } = req.query;
if (req.method === 'GET') {
try {
const shoppingLists = await prisma.List.findMany({ where: { userId: userId }});
res.status(200).json({lists: shoppingLists});
}
catch (error) {
console.log(error);
res.status(500).json({ message: 'Something went wrong. Please try again'});
}
}
else {
res.status(500).json({message: 'Invalid method requested!'});
}
}
The next layer, is the abstraction one which sent the final result to getServerSideProps. I created this because I need to fetch alot of requests and it would be too messy...
export const getAllLists = async userId => {
try {
const lists = await axios.get(`/api/get-all-lists/${userId}`);
return lists;
}
catch (error) {
console.log('Abstraction layer error: ', error);
return 'Something went wrong. Please try again later';
}
}
The problem arise here. In the postman I have the right result. In postman I use http://localhost:3000/api/get-all-lists/clbcpc0hi0002sb1wsiea3q5d and the server sent me the array specified.
But this function does not work and send me this error:
Abstraction layer error: TypeError [ERR_INVALID_URL]: Invalid URL
at new NodeError (node:internal/errors:371:5)
at onParseError (node:internal/url:552:9)
at new URL (node:internal/url:628:5)
at dispatchHttpRequest (file:///Users/sasdaniel/Desktop/massage/node_modules/axios/lib/adapters/http.js:176:20)
at new Promise (<anonymous>)
at http (file:///Users/sasdaniel/Desktop/massage/node_modules/axios/lib/adapters/http.js:112:10)
at Axios.dispatchRequest (file:///Users/sasdaniel/Desktop/massage/node_modules/axios/lib/core/dispatchRequest.js:51:10)
at Axios.request (file:///Users/sasdaniel/Desktop/massage/node_modules/axios/lib/core/Axios.js:142:33)
at Axios.<computed> [as get] (file:///Users/sasdaniel/Desktop/massage/node_modules/axios/lib/core/Axios.js:168:17)
at Function.wrap [as get] (file:///Users/sasdaniel/Desktop/massage/node_modules/axios/lib/helpers/bind.js:5:15) {
input: '/api/get-all-lists/clbcpc0hi0002sb1wsiea3q5d',
code: 'ERR_INVALID_URL'
}
I also tried to paste the localhost in the browser and it have no problem.
You could extract the functionality into /lib/getAllList.js:
import prisma from './prisma';
export default async function getAllLists(userId) {
return await prisma.List.findMany({ where: { userId: userId }});
}
Then use it in your API route:
import getAllLists from '../../../lib/getAllLists';
export default async function handler(req, res) {
const { userId } = req.query;
if (req.method === 'GET') {
try {
const shoppingLists = await getAllLists(userId);
res.status(200).json({lists: shoppingLists});
}
catch (error) {
console.log(error);
res.status(500).json({ message: 'Something went wrong. Please try again'});
}
}
else {
res.status(500).json({message: 'Invalid method requested!'});
}
}
Then use it in getServerSideProps:
import getAllLists from 'path/to/lib/getAllLists';
export async function getServerSideProps(context) {
const { userId } = context.params;
const shoppingLists = await getAllLists(userId);
return {
props: {
shoppingLists,
},
};
}
How to resolve nextjs problem?
Error: Error serializing .tariffs returned from getServerSideProps in "/".
Reason: undefined cannot be serialized as JSON. Please use null or omit this value.
export default function Home({ tariffs}) {
console.log(tariffs);
return (
<div className="wrapper"></div>
)
}
export async function getServerSideProps() {
const tariffs= await getTariffs();
return {
props: {
tariffs: tariffs,
},
};
}
My request function
import axios from "./axios";
import { getToken } from "../../helpers/storages";
export const getTariffs = async () => {
let res = await axios.get(`categories?access_token=${getToken()}`);
return res;
};
I want to use firebase to authenticate users and then firebase functions to insert users into Hasura but having problems with the firebase functions.
When I try to create a user from the app the "registerUser" function, which can be found below, it ends with an error:
Error detected in registerUser:
{"#type":"type.googleapis.com/google.devtools.clouderrorreporting.v1beta1.Insight",
"errorGroup":"CLic1cmw6emOsAE",
"errorEvent":{"message":"Error: The uid must be a non-empty string with at most 128 characters.
at FirebaseAuthError.FirebaseError [as constructor] (/srv/node_modules/firebase-admin/lib/utils/error.js:42:28)
at FirebaseAuthError.PrefixedFirebaseError [as constructor] (/srv/node_modules/firebase-admin/lib/utils/error.js:88:28)\
at new FirebaseAuthError (/srv/node_modules/firebase-admin/lib/utils/error.js:147:16)
at AuthRequestHandler.AbstractAuthRequestHandler.setCustomUserClaims (/srv/node_modules/firebase-admin/lib/auth/auth-api-request.js:996:35)
at Auth.BaseAuth.setCustomUserClaims (/srv/node_modules/firebase-admin/lib/auth/auth.js:342:40)
at exports.registerUser.functions.https.onCall (/srv/index.js:32:18)
at func (/srv/node_modules/firebase-functions/lib/providers/https.js:272:32)
at corsHandler (/srv/node_modules/firebase-functions/lib/providers/https.js:292:44)\n at cors (/srv/node_modules/cors/lib/index.js:188:7)
at /srv/node_modules/cors/lib/index.js:224:17","eventTime":"2020-06-10T08:25:03.017Z","serviceContext":{"service":"registerUser","resourceType":"cloud_function"}}}
If I instead create a user directly via the firebase console my "processSignUp" runs
but ends with another error:
ReferenceError: fetch is not defined
at GraphQLClient.<anonymous> (/srv/node_modules/graphql-request/dist/src/index.js:108:25)
at step (/srv/node_modules/graphql-request/dist/src/index.js:44:23)
at Object.next (/srv/node_modules/graphql-request/dist/src/index.js:25:53)
at /srv/node_modules/graphql-request/dist/src/index.js:19:71
at new Promise (<anonymous>)
at __awaiter (/srv/node_modules/graphql-request/dist/src/index.js:15:12)
at GraphQLClient.request (/srv/node_modules/graphql-request/dist/src/index.js:98:16)
at exports.processSignUp.functions.auth.user.onCreate (/srv/index.js:60:25)
at cloudFunction (/srv/node_modules/firebase-functions/lib/cloud-functions.js:132:23)
at /worker/worker.js:825:24
I've tried pretty much everything I could think of. I've used https://hasura.io/jwt-config/ to setup the JWT on Heroku. I've triple checked passwords and graphQL endpoint. I have no problems with the mutations or query variables when I play around in hasura console but I'm unable to connect the firebase functions to hasura. Thanks in advance.
functions/index.js
...
const client = new request.GraphQLClient(
"https://app-name.herokuapp.com/v1/graphql",
{
headers: {
"content-type": "application/json",
"x-hasura-admin-secret": "Password",
},
}
);
...
// On register.
exports.registerUser = functions.https.onCall((data) => {
const { email, password } = data;
try {
const userRecord = admin.auth().createUser({ email, password });
const customClaims = {
"https://hasura.io/jwt/claims": {
"x-hasura-default-role": "user",
"x-hasura-allowed-roles": ["user"],
"x-hasura-user-id": userRecord.uid,
},
};
admin.auth().setCustomUserClaims(userRecord.uid, customClaims);
return userRecord.toJSON();
} catch (e) {
let errorCode = "unknown";
let msg = "Something went wrong, please try again later";
if (e.code === "auth/email-already-exists") {
errorCode = "already-exists";
msg = e.message;
}
throw new functions.https.HttpsError(errorCode, msg, JSON.stringify(e));
}
});
...
// On sign up.
exports.processSignUp = functions.auth.user().onCreate(async (user) => {
const { uid: id, email } = user;
const mutation = `
mutation($id: String!, $email: String) {
insert_users(objects: [{
id: $id,
email: $email,
}]) {
affected_rows
}
}
`;
try {
const data = await client.request(mutation, { id, email });
return data;
} catch (e) {
throw new functions.https.HttpsError("invalid-argument", e.message);
}
});
In the package.json for your functions, try changing the node engine to 10 and your grapql-request package to 1.8.2.
I write application in React an Redux and I have a case that I have to send request to some resource when specific action was called and response of type 'text/html' write to state. This resource can return status 200 or 404, and I cannot write correct test for case with response 404.
To run tests I use jest library.
Action.js:
export const actions = {
GET_RESOURCE_SUCCESS: 'GET_RESOURCE_SUCCESS',
GET_RESOURCE_FAILURE: 'GET_RESOURCE_FAILURE'
};
export const getResourceSuccess = (response) => ({
type: actions.GET_RESOURCE_SUCCESS,
payload: response
});
export const getResourceFailure = () => ({
type: actions.GET_RESOURCE_FAILURE
});
Reducer.js:
import { handleActions } from 'redux-actions';
import { actions } from './Action';
const initialState = {
content: ''
};
export const getResourceReducer = handleActions(
{
[actions.GET_RESOURCE_SUCCESS]: (state, action) => ({ ...state, content: action.payload })
},
{
[actions.GET_RESOURCE_FAILURE]: () => ({ initialState })
},
initialState
);
In brief: when resource returns status 200 and content exists I want to overwrite content from initialState and call action GET_RESOURCE_SUCCESS, when resource returns status 404 and content doesn't exist I want not to overwrite the content and call action GET_RESOURCE_FAILURE.
GetResourceEpic.js:
import { ajax } from 'rxjs/observable/dom/ajax';
import { combineEpics } from 'redux-observable';
import { Observable } from 'rxjs';
import { getResourceSuccess, getResourceFailure } from '../Action';
const specificActionTypes = [
'SPECIFIC_ACTION_ONE',
'SPECIFIC_ACTION_TWO'
];
const getResource = () => ajax({
method: 'GET',
url: 'http://example.com',
headers: {
Accept: 'text/html'
},
crossDomain: true,
responseType: 'text/html'
});
const getResourceEpic = (action$, store) => action$
.filter(action => specificActionTypes.includes(action.type))
.flatMap(() => getResource()
// when response has status 200 and field response call getResourceSuccess
.map(({ response }) => getResourceSuccess(response))
// when response has status 404 and doesn't have field response call getResourceFailure
.catch(() => {
// helper statement to show in browser that the .catch() was called
console.log('Error');
return getResourceFailure();
})
);
export default combineEpics(
getResourceEpic
);
And it works in generally, but I get two errors:
first:
Uncaught TypeError: You provided an invalid object where a stream was expected. You can provide an Observable, Promise, Array, or Iterable.
at Object.subscribeToResult (subscribeToResult.js:73)
at CatchSubscriber../node_modules/rxjs/operator/catch.js.CatchSubscriber.error (catch.js:111)
at MapSubscriber../node_modules/rxjs/Subscriber.js.Subscriber._error (Subscriber.js:128)
at MapSubscriber../node_modules/rxjs/Subscriber.js.Subscriber.error (Subscriber.js:102)
at AjaxSubscriber../node_modules/rxjs/Subscriber.js.Subscriber._error (Subscriber.js:128)
at AjaxSubscriber../node_modules/rxjs/Subscriber.js.Subscriber.error (Subscriber.js:102)
at XMLHttpRequest.xhrReadyStateChange (AjaxObservable.js:327)
at XMLHttpRequest.d (raven.js:363)
and second:
Could not consume error: TypeError: Cannot read property 'length' of null
at getLinesAround (http://localhost:3000/static/js/bundle.js:47197:74)
at http://localhost:3000/static/js/bundle.js:47537:402
at Array.map (native)
at _callee2$ (http://localhost:3000/static/js/bundle.js:47517:54)
at tryCatch (http://localhost:3000/static/js/bundle.js:58220:40)
at Generator.invoke [as _invoke] (http://localhost:3000/static/js/bundle.js:58458:22)
at Generator.prototype.(anonymous function) [as next] (http://localhost:3000/static/js/bundle.js:58272:21)
at step (http://localhost:3000/static/js/bundle.js:47553:191)
at http://localhost:3000/static/js/bundle.js:47553:361
raven.js:51
And mentioned above problems don't allow me to write a tests, because only responses with status 200 pass the tests, other throws errors.
it('should dispatch GET_RESOURCE_SUCCESS when SPECIFIC_ACTION_ONE was dispatched', async () => {
store = mockStore();
const response = 'some content';
nock('http://example.com')
.get('/')
.reply(200, response);
const payload = { type: 'SPECIFIC_ACTION_ONE' };
// specificActionOne() produces and action of type 'SPECFIC_ACTION_ONE'
const action$ = ActionsObservable.of(specificActionOne(payload));
const resultAction = await getResourceEpic(action$, store).toPromise();
expect(resultAction)
.toEqual(getResourceSuccess(response));
});
And test above pass, but case with status equal to 404 doesn't pass:
it('should dispatch GET_RESOURCE_FAILURE when SPECIFIC_ACTION_ONE was dispatched', async () => {
store = mockStore();
nock('http://example.com')
.get('/')
.reply(404);
const payload = { type: 'SPECIFIC_ACTION_ONE' };
const action$ = ActionsObservable.of(specificActionOne(payload));
const resultAction = await getResourceEpic(action$, store).toPromise();
expect(resultAction)
.toEqual(getResourceFailure());
});
And test above doesn't pass and I get the result:
TypeError: You provided an invalid object where a stream was expected. You can provide an Observable, Promise, Array, or Iterable.
at Object.subscribeToResult (node_modules/rxjs/util/subscribeToResult.js:73:27)
at CatchSubscriber.Object.<anonymous>.CatchSubscriber.error (node_modules/rxjs/operator/catch.js:111:42)
at MapSubscriber.Object.<anonymous>.Subscriber._error (node_modules/rxjs/Subscriber.js:128:26)
at MapSubscriber.Object.<anonymous>.Subscriber.error (node_modules/rxjs/Subscriber.js:102:18)
at AjaxSubscriber.Object.<anonymous>.Subscriber._error (node_modules/rxjs/Subscriber.js:128:26)
at AjaxSubscriber.Object.<anonymous>.Subscriber.error (node_modules/rxjs/Subscriber.js:102:18)
at XMLHttpRequest.xhrReadyStateChange [as onreadystatechange] (node_modules/rxjs/observable/dom/AjaxObservable.js:327:32)
at XMLHttpRequest.callback.(anonymous function) (node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:289:32)
at invokeEventListeners (node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:219:27)
at invokeInlineListeners (node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:166:7)
at EventTargetImpl._dispatch (node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:122:7)
at EventTargetImpl.dispatchEvent (node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:87:17)
at XMLHttpRequest.dispatchEvent (node_modules/jsdom/lib/jsdom/living/generated/EventTarget.js:61:35)
at readyStateChange (node_modules/jsdom/lib/jsdom/living/xmlhttprequest.js:829:9)
at Request.properties.client.on (node_modules/jsdom/lib/jsdom/living/xmlhttprequest.js:947:7)
at Request.emit (events.js:132:15)
at IncomingMessage.<anonymous> (node_modules/request/request.js:1085:12)
at Object.onceWrapper (events.js:219:13)
at IncomingMessage.emit (events.js:132:15)
at endReadableNT (_stream_readable.js:1101:12)
at process._tickCallback (internal/process/next_tick.js:114:19)
The function passed to catch has to return an observable. You are returning an action.
Instead, you should do this:
import { of } from 'rxjs/observable/of';
...
.catch(() => {
console.log('Error');
return of(getResourceFailure());
})