记录 apollo-server GraphQL 查询和每个请求的变量

Posted

技术标签:

【中文标题】记录 apollo-server GraphQL 查询和每个请求的变量【英文标题】:Log apollo-server GraphQL query and variables per request 【发布时间】:2019-06-13 20:28:17 【问题描述】:

使用 apollo-server 2.2.1 或更高版本时,如何为每个请求记录查询和变量?

这似乎是一个简单的要求和常见用例,但文档是 very vague,传递给 formatResponsequery 对象 no longer 具有 queryStringvariables 属性。

【问题讨论】:

【参考方案1】:

使用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【参考方案2】:

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 包中。

【讨论】:

这可能是要走的路,但似乎woefully undocumented。顺便说一句,代码在没有安装 graphql-extensions 的情况下工作。 你是对的@DanDascalescu,这台 ATM 绝对没有文档......希望这在不久的将来会有所改善。同时,如果您想了解更多可用的生命周期方法,请查看at this class definition。 Apollo 服务器现在有 documentation for plugins 这个答案已经过时,因为扩展已被弃用。请改用插件,请参阅@amoe 的以下帖子【参考方案3】:

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; ?我的意思是,我认为上下文应该在使用“函数”覆盖时返回一个对象。【参考方案4】:

如果我必须记录查询和变量,我可能会使用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`)
)

【讨论】:

这个解决方案比Amit's much simpler one有什么优势? 我比他早两天给出了答案 这实际上是一个更灵活的解决方案,它真的帮助了我

以上是关于记录 apollo-server GraphQL 查询和每个请求的变量的主要内容,如果未能解决你的问题,请参考以下文章

使用 graphql 和 apollo-server 在解析器中获取会话

graphql apollo-server 中的文件上传错误

如何修复错误:使用 graphql 在 apollo-server 中多次定义类型“Extra”

在 apollo-server 中将网关上的联合类型转换为服务 GraphQL 中的标量类型

外部 WebSocket 服务器上的 Apollo-Server GraphQL 订阅

如何在 graphql apollo-server 变异解析器中发出错误信号?