是否可以为 Apollo Server 附带的 GraphQL Playground 定义 HTTP 标头?

Posted

技术标签:

【中文标题】是否可以为 Apollo Server 附带的 GraphQL Playground 定义 HTTP 标头?【英文标题】:Is it possible to define the HTTP headers for the GraphQL Playground that comes with Apollo Server? 【发布时间】:2020-11-01 16:25:34 【问题描述】:

我想为 GraphQL Playground 定义一些 http 标头,默认启用和/或始终启用。本质上,我想补充:

"apollographql-client-name": "playground"
"apollographql-client-version": "yada-yada"

能够将来自 Playground 的请求与 Apollo Studio 上的任何其他请求区分开来。最好的方法是什么?

GraphQL Playground 我指的是 Apollo 运行的一个,这里记录的那个:https://www.apollographql.com/docs/apollo-server/testing/graphql-playground/

我当前的 ApolloServer 配置如下所示:

let apolloServerExpressConfig: ApolloServerExpressConfig = 
  schema: schema,
  playground: 
    settings: 
      "request.credentials": "include",
    ,
  ,

如果我添加标签以尝试定义标题,如下所示:

let apolloServerExpressConfig: ApolloServerExpressConfig = 
  schema: schema,
  playground: 
    settings: 
      "request.credentials": "include",
    ,
    tabs: [
      headers: 
        "apollographql-client-name": "playground",
        "apollographql-client-version": "yada-yada",
      ,
    ],
  ,

GraphQL 游乐场在重新加载页面时不再恢复所有选项卡及其查询,这非常有用。我认为一旦您定义了标签,就会删除一些自动标签管理。我很高兴为新标签创建定义了默认标题,如果这些标题暴露给客户端就可以了。

我的应用已经定义了标头,因此,我可以区分应用和查询它的任何其他内容,但我想区分我的应用、游乐场和其他任何内容(后一组应该为空)。

【问题讨论】:

【参考方案1】:

更新:

https://github.com/apollographql/apollo-server/issues/1982#issuecomment-511765175

直接使用 GraphQL Playground Express 中间件 [...] 这将允许您利用 Express 中间件 req 对象,并相应地设置标题。

这是一个工作示例:

const app                   = require('express')()
const  ApolloServer, gql  = require('apollo-server-express')

// use this directly
  const expressPlayground   = require('graphql-playground-middleware-express').default

// just some boilerplate to make it runnable
  const typeDefs = gql`type Book  title: String author: String  type Query  books: [Book] `
  const books = [ title: 'Harry Potter and the Chamber of Secrets', author: 'J.K. Rowling' ,  title: 'Jurassic Park', author: 'Michael Crichton' ]
  const resolvers =  Query:  books: () => books  
  const server = new ApolloServer( typeDefs, resolvers );

//
// the key part 
//
  const headers = JSON.stringify(
    "apollographql-client-name"   : "playground",
    "apollographql-client-version": "yada-yada" ,
  )
  app.get('/graphql', expressPlayground(
    endpoint: `/graphql?headers=$encodeURIComponent(headers)`,
  ))
  server.applyMiddleware( app )

//
// 
//

// just some boilerplate to make it runnable
app.listen( port: 4000 , () => console.log(`? Server ready at http://localhost:4000$server.graphqlPath`))

页面重新加载后,所有选项卡及其内容都会恢复。


回答原问题:

Apollo Server GraphQL Playground 的含义并不完全清楚。你的用例是什么。

有一个桌面应用程序,一个网络应用程序,您可以将 GraphQL Playground 作为一个模块包含到您的前端,或者作为您的后端的中间件。

对于最简单的情况:切换到“HTTP HEADERS”选项卡,将标头添加为 JSON:


  "apollographql-client-name": "playground",
  "apollographql-client-version": "yada-yada",

对于前端Playground,您可以将带有headers 属性的tabs 传递给<Playground/>

<Playground
  ...
  tabs=[
    name: 'Tab 1',
    headers: 
      "apollographql-client-name"   : "playground",
      "apollographql-client-version": "yada-yada" ,
    
    ...
  ]
/>,

对于后端,您也可以使用headers

new ApolloServer(
  ...
  playground: 
    ...
    tabs: [
      ...
      headers: ...
    ],
  ,
)

你也可以

将来自 Playground 的请求与来自实际应用的请求区分开来

通过相反的方式:为您的实际应用添加额外的标题。

【讨论】:

定义“选项卡”打破了 GraphQL Playground 在重新加载时保留所有选项卡及其查询和变量的魔力。它只是覆盖它们。 @pupeno 我已经更新了答案。如果您对graphql-playground-middleware-express 没有异议,那么您就可以开始了。 我看到这个问题很久以前就有了。 @x00 你能回答这个问题吗:***.com/questions/69212790/…?.【参考方案2】:

Apollo-server-plugin-http-headers

允许您在解析器中轻松设置 HTTP 标头和 Cookie。这在 apollo-server-lambda 中特别有用,因为您没有任何其他选项可以设置标头或 cookie。

它的工作方式很简单:在上下文中放置一个 cookie 数组和一个 header 数组;然后,您可以在解析器中访问它们(因此添加、更改或删除标头和 cookie)。在您的请求发送到客户端之前,此插件会遍历数组并将每个项目添加到 HTTP 响应中。逻辑很简单,实际上文档比源代码长。

用法 - 标题

在解析器中设置标题:

context.setHeaders.push( key: "headername", value: "headercontent" );

完整示例:

const resolvers = 
    Query: 
        hello: async (parent, args, context, info) => 
            context.setHeaders.push( key: "X-TEST-ONE", value: "abc" );
            context.setHeaders.push( key: "X-TEST-TWO", value: "def" );
            return "Hello world!";
        
    
;

【讨论】:

这看起来像是发送到客户端的标头,而不是从 GraphQL Playground 发送到服务器的标头。我读错了吗? 你能看看这个并试一试吗? github.com/apollographql/apollo-server/issues/2279 @pupeno 你说得对,这个插件设置响应头。看source code @NadeemTaj,嗯...您提到的问题与问题有何关联? 看来我太兴奋了。我应该分享这个 Playground 选项卡选项似乎被忽略了 #1457。 github.com/apollographql/apollo-server/issues/1457.

以上是关于是否可以为 Apollo Server 附带的 GraphQL Playground 定义 HTTP 标头?的主要内容,如果未能解决你的问题,请参考以下文章

是否可以使用 Apollo Server 在服务器端本地执行突变或查询

Apollo-server 2 验证中间件

Apollo Server 2.x express 中间件

Apollo-server-express 内省已禁用,但仍然可以通过 websocket 连接

GraphQL Apollo Server,如何使字段将空字符串注册为空

使用替代 GraphQL 客户端连接到 Apollo Server