express-graphql : context is always undefined - node.js

I have a simple implementation of graphQl on my api, but can't seem to get any other arguments than args from the resolvers. The code is pretty simple, so it shouldn't cause any issue :
const bindGraphqlModule = (app) => {
app.use(
"/graphql",
graphqlHTTP(() => {
return {
schema: graphQLSchema,
rootValue: resolvers,
context: {
test: "hi ?"
},
graphiql: process.env.NODE_ENV !== "production",
};
})
);
};
and then my resolver :
const resolver = async (args, context, test) => {
console.log(context, test);
const { email, password } = args;
...
Args are accessible normally, but context and test are both undefined. Any clue ?

My bad, i actually englobed resolvers in a function to handle error, and didn't pass the context through totally. Solved

Related

How to deep mock Prisma Client in JavaScript (not TypeScript)?

I'm want to unit test Next.js API route with Prisma in JavaScript. Unfortunately, the Prisma's unit testing guide is written for Typescript.
I have jest.config.js which will setup the mock in jest.setup.js
const nextJest = require("next/jest");
const createJestConfig = nextJest({
dir: "./",
});
const config = {
setupFilesAfterEnv: ["<rootDir>/jest.setup.js"],
moduleDirectories: ["node_modules", "<rootDir>/"],
moduleNameMapper: {
"#/(.*)$": "<rootDir>/$1",
},
};
module.exports = createJestConfig(config);
and this is how I configured the mock in jest.setup.js
import prisma from "#/utils/client";
jest.mock("#/utils/client", () => ({
__esModule: true,
default: {
user: {
findMany: jest.fn(),
},
// ... and each and everyone of the entities
},
}));
export const prismaMock = prisma;
and the following test case passed
describe("Calculator", () => {
it("renders a calculator", async () => {
await prismaMock.user.findMany.mockResolvedValue(["abc]);
const { req, res } = createMocks();
await handler(req, res);
expect(res._getStatusCode()).toBe(200);
expect(res._getData()).toBe('["abc"]');
});
});
With this approach, I have to mock each and everyone of the models and function in jest.setup.js. Is there a way to mock all the models and functions automatically? Is there a similar JavaScript library which provides mockDeep from jest-mock-extended?

How to add query params to context of apollo-server-express

I'm using apollo-server-express as so right now:
import { ApolloServer } from 'apollo-server-express';
import { WebApp } from 'meteor/webapp';
import { getUser } from 'meteor/apollo';
import schema from './api';
const server = new ApolloServer({
schema,
context: async ({ req }) => {
const user = await getUser(req.headers.authorization);
return {
user,
};
},
playground: process.env.NODE_ENV === 'development',
introspection: true,
uploads: false,
});
server.applyMiddleware({
app: WebApp.connectHandlers,
path: '/graphql',
});
I'd like to add another field to the context which has all the query params from the URL my user is visiting.
It seems that the req object passed to the context function by apollo-server-express is of type express.Request which ought to have a req.query object. However, when I try to access that like so:
context: async ({ req }) => {
console.log('### query', req.query);
console.log('### params', req.params);
const user = await getUser(req.headers.authorization);
return {
user,
};
},
and visit my app at http://localhost:3000/u/3q2PcjRwyiqR2ywHM/BK2CiG7fN3P7Z5xvy?editToken=qdj3RRYjCuMxFNRnz (note the ?editToken=...)
I see the following log lines:
I20220417-15:08:54.477(-5)? ### query {}
I20220417-15:08:54.478(-5)? ### params undefined
I20220417-15:08:54.570(-5)? ### query {}
I20220417-15:08:54.571(-5)? ### params undefine
What is the correct way to access URL query params when creating the context for apollo-server-express? I'm specifically trying to add the editToken to the context.

Next.js middleware always return null as body

Request has a body property, but it seems to always be null for me in middleware functions.
If reading the body is not supported in middleware it would be nice for the docs to note that, and maybe for NextRequest to throw a helpful error when the body is accessed. The current behavior is a bit confusing.
import { NextRequest, NextResponse } from "next/server";
const middleware = (req = NextRequest, ev) => {
console.log("hey", req.body); // hey null
};
export default middleware;
export const config = {
api: {
bodyParser: {
sizeLimit: "500kb",
responseLimit: "3mb",
},
},
};
Now this seems to work
Just do await res.json()

GraphQL: Creating and Returning an Object in a Resolver?

I've got a mutation resolver that I call directly from the server like this:
import {graphql} from "graphql";
import {CRON_JOB_TO_FIND_USERS_WHO_HAVE_GONE_OFFLINE_MUTATION} from "../../query-library";
import AllResolvers from "../../resolvers";
import AllSchema from "../../schema";
import {makeExecutableSchema} from "graphql-tools";
const typeDefs = [AllSchema];
const resolvers = [AllResolvers];
const schema = makeExecutableSchema({
typeDefs,
resolvers
});
const {data, errors} = await graphql(
schema,
CRON_JOB_TO_FIND_USERS_WHO_HAVE_GONE_OFFLINE_MUTATION,
{},
{caller: 'synced-cron'},
{timeStarted: new Date().toISOString().slice(0, 19).replace('T', ' ')}
)
The mutation resolver is called and runs correctly. I don't need it to return anything, but GraphQL throws a warning if it doesn't, so I'd like it to return an object, any object.
So I'm trying it like this:
SCHEMA
cronJobToFindUsersWhoHaveGoneOffline(timeStarted: String): myUserData
QUERY
// note -- no gql. This string is passed directly to function graphql()
// where it gets gql applied to it.
const CRON_JOB_TO_FIND_USERS_WHO_HAVE_GONE_OFFLINE_MUTATION = `
mutation ($timeStarted: String){
cronJobToFindUsersWhoHaveGoneOffline(timeStarted: $timeStarted){
id,
},
}
`;
RESOLVER
cronJobToFindUsersWhoHaveGoneOffline(parent, args, context) {
return Promise.resolve()
.then(() => {
// there is code here that finds users who went offline if any
return usersWhoWentOffline;
})
.then((usersWhoWentOffline) => {
// HERE'S WHERE I HAVE TO RETURN SOMETHING FROM THE RESOLVER
let myUserDataPrototype = {
__typename: 'myUserData',
id: 'not_a_real_id'
}
const dataToReturn = Object.create(myUserDataPrototype);
dataToReturn.__typename = 'myUserData';
dataToReturn.id = 'not_a_real_id';
return dataToReturn; <==GRAPHQL IS NOT HAPPY HERE
})
.catch((err) => {
console.log(err);
});
},
}
GraphQL throws this warning:
data [Object: null prototype] {
cronJobToFindUsersWhoHaveGoneOffline: [Object: null prototype] { id: 'not_a_real_id' }
}
errors undefined
I have tried all kinds of different ways to fix this, but I haven't figured out the correct syntax yet.
What is a good way to handle this?
That doesn't appear to be a warning. That looks like you're writing the result to the console somewhere.

Need to find the error with connecting subscription with schema stitching

I am using apollo-server-express for graphql back-end. I am going to process only mutations there, but I want to redirect query and subscription on hasura by means of schema stitching with introspection. Queries through apollo-server to hasura are working fine and returning the expected data.
But subscriptions are not working and I am getting this error: " Expected Iterable, but did not find one for field subscription_root.users".
And besides, server hasura is receiving events:
But apollo-server resents the answer from hasura. It is not the first day I suffer with this and I can not understand what the problem is.
In the editor hasura subscriptions work.
Link to full code
If you need any additional info, I will gladly provide it to you.
import {
introspectSchema,
makeExecutableSchema,
makeRemoteExecutableSchema,
mergeSchemas,
transformSchema,
FilterRootFields
} from 'graphql-tools';
import { HttpLink } from 'apollo-link-http';
import nodeFetch from 'node-fetch';
import { resolvers } from './resolvers';
import { hasRoleResolver } from './directives';
import { typeDefs } from './types';
import { WebSocketLink } from 'apollo-link-ws';
import { split } from 'apollo-link';
import { getMainDefinition } from 'apollo-utilities';
import { SubscriptionClient } from 'subscriptions-transport-ws';
import * as ws from 'ws';
import { OperationTypeNode } from 'graphql';
interface IDefinitionsParams {
operation?: OperationTypeNode,
kind: 'OperationDefinition' | 'FragmentDefinition'
}
const wsurl = 'ws://graphql-engine:8080/v1alpha1/graphql';
const getWsClient = function (wsurl: string) {
const client = new SubscriptionClient(wsurl, {
reconnect: true,
lazy: true
}, ws);
return client;
};
const wsLink = new WebSocketLink(getWsClient(wsurl));
const createRemoteSchema = async () => {
const httpLink = new HttpLink({
uri: 'http://graphql-engine:8080/v1alpha1/graphql',
fetch: (nodeFetch as any)
});
const link = split(
({ query }) => {
const { kind, operation }: IDefinitionsParams = getMainDefinition(query);
console.log('kind = ', kind, 'operation = ', operation);
return kind === 'OperationDefinition' && operation === 'subscription';
},
wsLink,
httpLink,
);
const remoteSchema = await introspectSchema(link);
const remoteExecutableSchema = makeRemoteExecutableSchema({
link,
schema: remoteSchema
});
const renamedSchema = transformSchema(
remoteExecutableSchema,
[
new FilterRootFields((operation, fieldName) => {
return (operation === 'Mutation') ? false : true; // && fieldName === 'password'
})
]
);
return renamedSchema;
};
export const createNewSchema = async () => {
const hasuraExecutableSchema = await createRemoteSchema();
const apolloSchema = makeExecutableSchema({
typeDefs,
resolvers,
directiveResolvers: {
hasRole: hasRoleResolver
}
});
return mergeSchemas({
schemas: [
hasuraExecutableSchema,
apolloSchema
]
});
};
Fixed by installing graphql-tools 4th version. It tutns out the editor did not even notice that I do not have this dependency and simply took the version of node_modules, which was installed by some other package. Problem was with version 3.x. Pull request is where the bug was fixed.
I had the same problem, different cause and solution.
My subscription was working well, until I introduced the 'resolve' key in
my subscription resolver:
Here is the 'Subscription' part of My resolver:
Subscription: {
mySubName: {
resolve: (payload) => {
console.log('In mySubName resolver, payload:',payload)
return payload;
},
subscribe:() => pubSub.asyncIterator(['requestsIncomplete']),
// )
},
The console.log proved the resolve() function was being called with a well structured payload (shaped the same as my Schema definiton - specifically the an object with a key named after the graphQL Subscriber, pointing to an array (array is an iterable):
In mySubName resolver, payload: { mySubName:
[ { id: 41,
...,
},
{...},
{...}
...
...
]
Even though I was returning that same unadulterated object, it caused the error expected Iterable, but did not find one for field "Subscription.mySubName"
When I commented out that resolve function all together, the subscription worked, which is further evidence that my payload was well structured, with the right key pointing to an iterable.
I must be mis-using the resolve field. From https://www.apollographql.com/docs/graphql-subscriptions/subscriptions-to-schema/
When using subscribe field, it's also possible to manipulate the event
payload before running it through the GraphQL execution engine.
Add resolve method near your subscribe and change the payload as you wish
so I am not sure how to properly use that function, specifically don't know what shape object to return from it, but using it as above breaks the subscription in the same manner you describe in your question.
I was already using graphql-tools 4.0.0, I upgraded to 4.0.8 but it made no difference.

Resources