Here's my problem: I'm trying to count the number of arguments that are received in order to write them in the access logs. I'm using apollo server started from an express, graphql as my API entry point and I'm using morgan library to write access logs.
I try to use the apollo plugins to retrieve information from the graphql request. I can find out from the plugins how many arguments I have, but I can't pass this information to the request context so that the morgan library can retrieve the number of arguments to write it.
I've made a .js file that sums up what I want to do with console.log for debbuging
const cors = require('cors');
const express = require('express');
const morgan = require('morgan');
const { json } = require('body-parser');
const { ApolloServer } = require('@apollo/server');
const { expressMiddleware } = require('@apollo/server/express4');
morgan.token('countID', (req) => {
console.log('req.countID', req.countID);
if (req.countID) return req.countID;
return '-';
});
const logger = morgan('[:date[clf]] ":method :url HTTP/:http-version" :status ":countID"', { stream: process.stdout });
const typeDefs = `#graphql
type Query {
hello(id: [ID!]!): String
}
`;
const resolvers = {
Query: {
hello: (parent, args, context, info) => {
const { id } = args;
return `id: ${id.length}`;
},
},
};
const countIDPlugin = {
requestDidStart() {
return {
executionDidStart() {
return {
willResolveField({ info, contextValue: resolverContext }) {
const args = info?.fieldNodes[0]?.arguments.filter((e) => e.name.value === 'id');
const countID = args[0]?.value?.values?.length
if (!countID) {
return;
}
console.log('plugin:', countID)
resolverContext.countID = countID;
console.log('resolverContext.countID: ', countID)
},
};
},
};
},
};
const server = new ApolloServer({
typeDefs,
resolvers,
introspection: true,
csrfPrevention: false,
plugins: [
countIDPlugin,
],
context: ({ req }) => ({ req }),
});
(async () => {
const app = express();
app.use(logger);
app.use(cors({
origin: '*',
allowedHeaders: ['Content-Type', 'x-api-key'],
method: ['GET', 'POST'],
}));
await server.start();
app.use('/graphql', cors(), json(), expressMiddleware(server, {}));
app.listen(3000, async () => {
console.log('Server up')
});
})();
With this js file, when i start my server and when i do graphql request, there is my log :
Server up
plugin: 3
resolverContext.countID: 3
req.countID undefined
[11/Mar/2024:19:47:00 +0000] "POST /graphql HTTP/1.1" 200 "-"
I don't know if it's the right solution to go through an apollo plugin to do what I want to do, I remain open to other proposals.
Thanks in advance
You can do this by adding context express to the middleware in this way:
app.use('/graphql', cors(), json(), expressMiddleware(server, {
context: async ({ req }) => req,
}));
In your willResolveField function you can then do
contextValue.res.req.countID = countID;
Here's the code in full and simplified
const cors = require('cors');
const express = require('express');
const morgan = require('morgan');
const { json } = require('body-parser');
const { ApolloServer } = require('@apollo/server');
const { expressMiddleware } = require('@apollo/server/express4');
morgan.token('countID', (req) => (req?.countID || '-'));
const logger = morgan('[:date[clf]] ":method :url HTTP/:http-version" :status ":countID"', { stream: process.stdout });
const typeDefs = `#graphql
type Query {
hello(id: [ID!]!): String
}
`;
const resolvers = {
Query: {
hello: (parent, args, context, info) => (`id: ${context.countID}`),
},
};
const countIDPlugin = {
requestDidStart() {
return {
executionDidStart() {
return {
willResolveField({ args, contextValue }) {
const countID = args?.id?.length;
if (!countID) { return; }
contextValue.res.req.countID = countID;
contextValue.countID = countID;
},
};
},
};
},
};
const server = new ApolloServer({
typeDefs,
resolvers,
introspection: true,
csrfPrevention: false,
plugins: [
countIDPlugin,
],
context: ({ req }) => ({ req }),
});
(async () => {
const app = express();
app.use(logger);
app.use(cors({
origin: '*',
allowedHeaders: ['Content-Type', 'x-api-key'],
method: ['GET', 'POST'],
}));
await server.start();
app.use('/graphql', cors(), json(), expressMiddleware(server, {
context: async ({ req }) => req,
}));
app.listen(3000, async () => {
console.log('Server up')
});
})();