Strapi V4 - Cannot read properties of undefined (reading 'use') - graphql

I have this resolver for graphql to find pet with slug.
In src/index.js
'use strict';
module.exports = {
/**
* An asynchronous register function that runs before
* your application is initialized.
*
* This gives you an opportunity to extend code.
*/
register({ strapi }) {
const extensionService = strapi.service("plugin::graphql.extension");
extensionService.use(({ strapi }) => ({
typeDefs: `
type Query {
pet(slug: String!): PetEntityResponse
}`,
resolvers: {
Query: {
pet: {
resolve: async (parent, args, context) => {
const { toEntityResponse } = strapi.service(
"plugin::graphql.format"
).returnTypes;
const data = await strapi.services["api::pet.pet"].find({
filters: { slug: args.slug },
});
const response = toEntityResponse(data.results[0]);
return response;
},
}
}
},
}));
},
/**
* An asynchronous bootstrap function that runs before
* your application gets started.
*
* This gives you an opportunity to set up your data model,
* run jobs, or perform some special logic.
*/
bootstrap(/*{ strapi }*/) {},
};
It worked at the beginning but after I restarted the server I got this error:
TypeError: Cannot read properties of undefined (reading 'use')
at register (/opt/app/src/index.js:13:22)
at Strapi.runLifecyclesFunctions (/opt/app/node_modules/#strapi/strapi/lib/Strapi.js:533:13)
at async Strapi.register (/opt/app/node_modules/#strapi/strapi/lib/Strapi.js:393:5)
at async Strapi.load (/opt/app/node_modules/#strapi/strapi/lib/Strapi.js:474:5)
at async Strapi.start (/opt/app/node_modules/#strapi/strapi/lib/Strapi.js:212:9)
error Command failed with exit code 1.
I tried to remove node_modules and yarn.lock and reinstall, but didn't work.

Related

Apollo GraphQL Lambda Handler Cannot read property 'method' of undefined

I am trying to run Apollo GraphQL server inside my AWS lambda. I'm using the library from here. I'm also using CDK to deploy my lambda and the REST API Gateway.
My infrastructure is as follows:
const helloFunction = new NodejsFunction(this, 'lambda', {
entry: path.join(__dirname, "lambda.ts"),
handler: "handler"
});
new LambdaRestApi(this, 'apigw', {
handler: helloFunction,
});
The lambda implementation is as follows:
const typeDefs = `#graphql
type Query {
hello: String
}`;
const resolvers = {
Query: {
hello: () => 'world',
},
};
const server = new ApolloServer({
typeDefs,
resolvers,
introspection: true,
})
console.log('###? running lambda')
export const handler = startServerAndCreateLambdaHandler(
server,
handlers.createAPIGatewayProxyEventV2RequestHandler(), {
middleware: [
async (event) => {
console.log('###? received event=' + JSON.stringify(event, null, 2))
return async (result) => {
console.log(("###? result=" + JSON.stringify(result, null, 2)))
result
}
}
]
});
When I POST to my endpoint with the appropriate query I get this error:
{
"statusCode": 400,
"body": "Cannot read property 'method' of undefined"
}
I'm seeing my logging inside the lambda as expected and I can confirm the error is being returned in the 'result' from within startServerAndCreateLambdaHandler(). This code is based on the example for the #as-integrations/aws-lambda library. I don't understand why this is failing.
Need to use:
handlers.createAPIGatewayProxyEventRequestHandler()
Instead of:
handlers.createAPIGatewayProxyEventV2RequestHandler()
So final code is:
export const handler = startServerAndCreateLambdaHandler(
server,
handlers.createAPIGatewayProxyEventRequestHandler(),
{
middleware: [
async (event) => {
console.log('###? received event=' + JSON.stringify(event))
}
]
}
);

Strapi custom logger configuration

I have got a Strapi v4 app with the following:
./config/logger.js
'use strict';
const {
winston,
formats: { prettyPrint, levelFilter },
} = require('#strapi/logger');
module.exports = {
transports: [
new winston.transports.Console({
level: 'debug',
format: winston.format.combine(
levelFilter('debug'),
prettyPrint({ timestamps: 'YYYY-MM-DD hh:mm:ss.SSS' })
),
}),
],
};
and additionally in my ./config/functions/bootstrap.js i have got the following code
'use strict';
/**
* An asynchronous bootstrap function that runs before
* your application gets started.
*
* This gives you an opportunity to set up your data model,
* run jobs, or perform some special logic.
*/
module.exports = () => {
console.log("Hello World!");
logger.log("debug","Hello Strapi app!");
};
Unfortunately i do not see it anywhere printed in my folder Strapi app or Web browser. Any idea that could help me?
Regards

apollo-server-lambda: Unable to determine event source based on event

I am using apollo-server-lambda for my app. I have create custom authoization http headers and it is required . if authoization: LETMEIN then it will return true and also return all data, if there is no any authoization or wrong authoization then it wll throw an error. For local development I used serverless-offline.In Local environment, it works as expected and here is the image but when I deploy my code to AWS, the api end does not work. It always throws me the error: here is the link.
I test my function AWS console. I am getting this error:
I did not get what I am doing wrong.
Here is my code
/* eslint-disable #typescript-eslint/no-var-requires */
import { ApolloServerPluginLandingPageGraphQLPlayground } from 'apollo-server-core';
import { ApolloServer, AuthenticationError } from 'apollo-server-lambda';
import schema from '../graphql/schema';
import resolvers from '../resolvers';
import runWarm from '../utils/run-warm';
export const authToken = (token: string) => {
if (token === 'LETMEIN') {
return;
} else {
throw new AuthenticationError('No authorization header supplied');
}
};
const server = new ApolloServer({
typeDefs: schema,
resolvers,
debug: false,
plugins: [ApolloServerPluginLandingPageGraphQLPlayground()],
context: ({ event }) => {
//console.log(context);
if (event.headers) {
authToken(event.headers.authorization);
}
},
});
export default runWarm(
server.createHandler({
expressGetMiddlewareOptions: {
cors: {
origin: '*',
credentials: true,
allowedHeaders: ['Content-Type', 'Origin', 'Accept'],
optionsSuccessStatus: 200,
maxAge: 200,
},
},
})
);
This is my Lambda function
/**
* Running warm functions help prevent cold starts
*/
const runWarm =
(lambdaFunc: AWSLambda.Handler): AWSLambda.Handler =>
(event, context, callback) => {
// Detect the keep-alive ping from CloudWatch and exit early. This keeps our
// lambda function running hot.
if (event.source === 'serverless-plugin-warmup') {
return callback(null, 'pinged');
}
return lambdaFunc(event, context, callback);
};
export default runWarm;
This is not a direct answer, but might help, and could be useful if anyone else (like me) found this thread because of the error "Unable to determine event source based on event" when using apollo-server-lambda.
That error is coming from #vendia/serverless-express which is being used by apollo-server-lambda.
Within serverless-express, in src/event-sources/utils.js, there is a function called getEventSourceNameBasedOnEvent(), which is throwing the error. It needs to find something in the event object, and after a bit of experimentation I found that writing the lambda function like this solved the issue for me:
const getHandler = (event, context) => {
const server = new ApolloServer({
typeDefs,
resolvers,
debug: true,
});
const graphqlHandler = server.createHandler();
if (!event.requestContext) {
event.requestContext = context;
}
return graphqlHandler(event, context);
}
exports.handler = getHandler;
Note that the context object is added to the event object with the key "requestContext"....that's the fix.
(Also note that I have defined typeDefs and resolvers elsewhere in the code)
I can't guarantee this is the ideal thing to do, but it did work for me.

Pubsub publish multiple events Apollo Server

I am using Apollo Server and I want to publish 2 events in the row from same resolver. Both subscriptions are working fine but only if I dispatch only one event. If I try to dispatch both, second subscription resolver never gets called. If I comment out the first event dispatch second works normally.
const publishMessageNotification = async (message, me, action) => {
const notification = await models.Notification.create({
ownerId: message.userId,
messageId: message.id,
userId: me.id,
action,
});
// if I comment out this one, second pubsub.publish starts firing
pubsub.publish(EVENTS.NOTIFICATION.CREATED, {
notificationCreated: { notification },
});
const unseenNotificationsCount = await models.Notification.find({
ownerId: notification.ownerId,
isSeen: false,
}).countDocuments();
console.log('unseenNotificationsCount', unseenNotificationsCount);// logs correct value
// this one is not working if first one is present
pubsub.publish(EVENTS.NOTIFICATION.NOT_SEEN_UPDATED, {
notSeenUpdated: unseenNotificationsCount,
});
};
I am using default pubsub implementation. There are no errors in the console.
import { PubSub } from 'apollo-server';
import * as MESSAGE_EVENTS from './message';
import * as NOTIFICATION_EVENTS from './notification';
export const EVENTS = {
MESSAGE: MESSAGE_EVENTS,
NOTIFICATION: NOTIFICATION_EVENTS,
};
export default new PubSub();
Make sure, that you use pubsub from context of apollo server, for example:
Server:
const server = new ApolloServer({
schema: schemaWithMiddleware,
subscriptions: {
path: PATH,
...subscriptionOptions,
},
context: http => ({
http,
pubsub,
redisCache,
}),
engine: {
apiKey: ENGINE_API_KEY,
schemaTag: process.env.NODE_ENV,
},
playground: process.env.NODE_ENV === 'DEV',
tracing: process.env.NODE_ENV === 'DEV',
debug: process.env.NODE_ENV === 'DEV',
});
and example use in resolver, by context:
...
const Mutation = {
async createOrder(parent, { input }, context) {
...
try {
...
context.pubsub.publish(CHANNEL_NAME, {
newMessage: {
messageCount: 0,
},
participants,
});
dialog.lastMessage = `{ "orderID": ${parentID}, "text": "created" }`;
context.pubsub.publish(NOTIFICATION_CHANNEL_NAME, {
notification: { messageCount: 0, dialogID: dialog.id },
participants,
});
...
}
return result;
} catch (err) {
log.error(err);
return sendError(err);
}
},
};
...
It has been a while since this moment.
I have also been a struggle with pubsub not working problem.
and I would like to see your ApolloClient setup code.
I changed my configurations with regard to graphql version and client-side setup.
graphql version : 14.xx.xx -> 15.3.0
const client = new ApolloClient({
uri: 'http://localhost:8001/graphql',
cache: cache,
credentials: 'include',
link: ApolloLink.from([wsLink, httpLink])
});
I want you to clarify link order, especially about httpLink, if you use in your case, "HttpLink is a terminating Link.", according to Apollo official site.
At first, I used link order [httpLink, wsLink].
Therefore, pubsub.publish didn't work.
I hope this answer will help some of graphql users.

custom render connected react component with mock axios response - getBy* query misleading exception

I have a problem with updating props in my test after some code refactor. I use custom render and mock axios request but my component doesn't rerender (?). In my component in async ComponentDidMount() I do POST request. When I do manual test in browser everything works fine.
I receive exception produced by getByText():
Unable to find an element with the text: /Tasty Metal Keyboard/i. This
could be because the text is broken up by multiple elements. In this
case, you can provide a function for your text matcher to make your
matcher more flexible.
/** import React, mockAxios etc. */
const middleware = applyMiddleware(thunk);
const inputRootPath = document.createElement('input');
inputRootPath.id = 'rootPath';
inputRootPath.hidden = true;
inputRootPath.value = 'http://localhost/';
/**
*
* #param {*} ui komponent
* #param {*} param { initialState, store }
*/
export function renderWithRedux(
ui,
{ initialState, store = createStore(rootReducer, initialState, compose(middleware)) } = {},
) {
return {
...render(
<Provider store={store}>
{ui}
</Provider>,
{ container: document.body.appendChild(inputRootPath) }
),
store,
};
}
test('should render annex list', async () => {
const agBuilder = () => {
return {
ID: faker.random.number(),
NM: faker.commerce.productName(),
};
};
const agreements = [agBuilder(), agBuilder(), agBuilder(), agBuilder()];
mockAxios.post.mockResolvedValueOnce({ data: { ANLST: agreements } });
const { getByText, } = await renderWithRedux(<ConnectedAgreements />);
const optionRE = new RegExp(`${agreements[0].NM}`, 'i');
expect(getByText(optionRE)).toBeInTheDocument();
mockAxios.post.mockClear();
});
mocks/axios.js
export default {
get: jest.fn().mockResolvedValue({ data: {} }),
post: jest.fn().mockResolvedValue({ data: {} }),
};
I found solution. It turns out that after some code refactor I have another reducer which takes dispatch action invoked in CDM. It destructure axios response so my test code should have:
mockAxios.post.mockResolvedValueOnce({ data: { ANLST: agreements, CLS: {}, EXLDT: {} } });
Missing CLS and EXLDT properties casue test fail. Jest however doesn't print error that something is missing or undefined ¯_(ツ)_/¯ . Exception produced by getByText() was misleading.

Resources