【发布时间】:2019-06-13 20:28:17
【问题描述】:
使用 apollo-server 2.2.1 或更高版本时,如何为每个请求记录查询和变量?
这似乎是一个简单的要求和常见用例,但文档是 very vague,传递给 formatResponse 的 query 对象 no longer 具有 queryString 和 variables 属性。
【问题讨论】:
标签: apollo-server
使用 apollo-server 2.2.1 或更高版本时,如何为每个请求记录查询和变量?
这似乎是一个简单的要求和常见用例,但文档是 very vague,传递给 formatResponse 的 query 对象 no longer 具有 queryString 和 variables 属性。
【问题讨论】:
标签: apollo-server
使用new plugins API,您可以使用与 Josep 的答案非常相似的方法,只是您的代码结构有所不同。
const BASIC_LOGGING = {
requestDidStart(requestContext) {
console.log("request started");
console.log(requestContext.request.query);
console.log(requestContext.request.variables);
return {
didEncounterErrors(requestContext) {
console.log("an error happened in response to query " + requestContext.request.query);
console.log(requestContext.errors);
}
};
},
willSendResponse(requestContext) {
console.log("response sent", requestContext.response);
}
};
const server = new ApolloServer(
{
schema,
plugins: [BASIC_LOGGING]
}
)
server.listen(3003, '0.0.0.0').then(({ url }) => {
console.log(`GraphQL API ready at ${url}`);
});
【讨论】:
willSendResponse 应该在与 didEncounterErrors 相同的上下文中返回,因为两者都依赖于 requestDidStart
Amit 的答案(今天)有效,但恕我直言,它有点笨拙,将来可能无法按预期工作,或者在某些情况下可能无法正常工作。
例如,当我看到它时我想到的第一件事是:“如果查询无效,那可能不起作用”,事实证明今天它在查询无效时确实有效.因为在当前实现中,在验证查询之前会评估上下文。但是,这是一个未来可能会改变的实现细节。例如,如果有一天 apollo 团队决定只在查询被解析和验证后评估上下文将是一种性能胜利怎么办?这实际上是我所期待的:-)
我想说的是,如果您只是想快速记录一些内容以便在 dev 环境中调试某些内容,那么 Amit 的解决方案绝对是您的最佳选择。
但是,如果您想要为生产环境注册日志,那么使用context 函数可能不是最好的主意。在这种情况下,我会安装 graphql-extensions 并将它们用于日志记录,例如:
const { print } = require('graphql');
class BasicLogging {
requestDidStart({queryString, parsedQuery, variables}) {
const query = queryString || print(parsedQuery);
console.log(query);
console.log(variables);
}
willSendResponse({graphqlResponse}) {
console.log(JSON.stringify(graphqlResponse, null, 2));
}
}
const server = new ApolloServer({
typeDefs,
resolvers,
extensions: [() => new BasicLogging()]
});
正如 Dan 指出的,不需要安装 graphql-extensions 包,因为它已集成在 apollo-server-core 包中。
【讨论】:
graphql-extensions 的情况下工作。
Dan 的解决方案主要解决了这个问题,但如果你想在不使用 express 的情况下记录它, 您可以在下面示例中显示的上下文中捕获它。
const server = new ApolloServer({
schema,
context: params => () => {
console.log(params.req.body.query);
console.log(params.req.body.variables);
}
});
【讨论】:
context: params => { console.log(params.req.body.query); console.log(params.req.body.variables); return emptyObject; }?我的意思是,我认为上下文应该在使用“函数”覆盖时返回一个对象。
如果我必须记录查询和变量,我可能会使用apollo-server-express,而不是apollo-server,这样我就可以在为我记录的graphql 之前添加一个单独的快速中间件:
const express = require('express')
const { ApolloServer } = require('apollo-server-express')
const { typeDefs, resolvers } = require('./graphql')
const server = new ApolloServer({ typeDefs, resolvers })
const app = express()
app.use(bodyParser.json())
app.use('/graphql', (req, res, next) => {
console.log(req.body.query)
console.log(req.body.variables)
return next()
})
server.applyMiddleware({ app })
app.listen({ port: 4000}, () => {
console.log(`? Server ready at http://localhost:4000${server.graphqlPath}`)
})
【讨论】: