【问题标题】:graphql-codegen error response from prismic来自棱镜的graphql-codegen错误响应
【发布时间】:2020-03-07 22:21:49
【问题描述】:

当尝试使用 graphql-codegen 从 Prismic 生成类型时,我收到以下错误:

graphql/types.tsx
    Failed to load schema from [object Object]:

        invalid json response body at https://my-project-name.prismic.io/graphql reason: Unexpected t
oken < in JSON at position 0

我猜它似乎正在返回 HTML(因此是 &lt;)。如果我在 Chrome 中访问 graphql url,我会得到 graphiql-editor。如果我转到 Postman 中的 url,我会收到 missing query parameter(这是预期的)错误,因此该路径似乎在这些环境中有效。我需要与 Prismic 一起使用的特定配置吗?

schema:
  - https://my-project-name.prismic.io/graphql:
    headers:
      Prismic-Ref: PRISMIC_REF
documents:
  - "graphql/**/*.ts"
generates:
  graphql/types.tsx:
    plugins:
      - "typescript"
      - "typescript-operations"
      - "typescript-react-apollo"
    config:
      noHOC: true
      noComponents: true
      noNamespaces: true
      withHooks: true

【问题讨论】:

    标签: graphql prismic.io


    【解决方案1】:

    我对这个工具不是很熟悉,但我猜默认情况下,这个工具会尝试使用 POST 方法调用 graphQL API。 出于缓存的原因,Prismic 目前只使用 GET,所以我很确定它与它有关。 希望对你有所帮助。

    【讨论】:

      【解决方案2】:

      这确实是因为 Prismic GraphQL api 使用 GET 而不是 POST 请求。实际上,我没有找到任何工具可以使用 GET 内省 GraphQL 端点。经过一番挖掘,想出了以下解决方案:

      1. 此代码基于prismic-apollo-link。由于我将它与 Next JS 结合使用(我需要同构 unfetch),因此我对其进行了轻微修改。如果你不使用 Next JS,你仍然需要它,因为我们需要 fetch 才能在 Node 中工作。
      import {ApolloClient} from 'apollo-client'
      import {InMemoryCache} from 'apollo-cache-inmemory'
      import {HttpLink} from 'apollo-link-http'
      import {setContext} from 'apollo-link-context'
      import Prismic from 'prismic-javascript'
      import fetch from 'isomorphic-unfetch'
      
      const baseEndpoint = 'https://<your project>.cdn.prismic.io'
      const accessToken = '<your access token>'
      
      export default function createApolloClient(initialState, ctx) {
        const primicClient = Prismic.client(`${baseEndpoint}/api`, {accessToken})
      
        const prismicLink = setContext((req, options) => {
          return primicClient.getApi().then(api => ({
            headers: {
              'Prismic-ref': api.masterRef.ref,
              ...options.headers,
              ...((api as any).integrationFieldRef
                ? {'Prismic-integration-field-ref': (api as any).integrationFieldRef}
                : {}),
              ...(accessToken ? {Authorization: `Token ${accessToken}`} : {}),
            },
          }))
        })
      
        const httpLink = new HttpLink({
          uri: `${baseEndpoint}/graphql`,
          useGETForQueries: true,
          fetch,
        })
      
        return new ApolloClient({
          ssrMode: Boolean(ctx),
          link: prismicLink.concat(httpLink),
          cache: new InMemoryCache().restore(initialState),
        })
      }
      
      
      1. 制作一个脚本来自省 Prismic GraphQL 服务器:
      import createApolloClient from '../apolloClient'
      import gql from 'graphql-tag'
      import path from 'path'
      import fs from 'fs'
      
      const client = createApolloClient({}, null)
      
      const main = async () => {
        try {
          const res = await client.query({
            query: gql`
              query IntrospectionQuery {
                __schema {
                  queryType {
                    name
                  }
                  mutationType {
                    name
                  }
                  subscriptionType {
                    name
                  }
                  types {
                    ...FullType
                  }
                  directives {
                    name
                    description
                    locations
                    args {
                      ...InputValue
                    }
                  }
                }
              }
      
              fragment FullType on __Type {
                kind
                name
                description
                fields(includeDeprecated: true) {
                  name
                  description
                  args {
                    ...InputValue
                  }
                  type {
                    ...TypeRef
                  }
                  isDeprecated
                  deprecationReason
                }
                inputFields {
                  ...InputValue
                }
                interfaces {
                  ...TypeRef
                }
                enumValues(includeDeprecated: true) {
                  name
                  description
                  isDeprecated
                  deprecationReason
                }
                possibleTypes {
                  ...TypeRef
                }
              }
      
              fragment InputValue on __InputValue {
                name
                description
                type {
                  ...TypeRef
                }
                defaultValue
              }
      
              fragment TypeRef on __Type {
                kind
                name
                ofType {
                  kind
                  name
                  ofType {
                    kind
                    name
                    ofType {
                      kind
                      name
                      ofType {
                        kind
                        name
                        ofType {
                          kind
                          name
                          ofType {
                            kind
                            name
                            ofType {
                              kind
                              name
                            }
                          }
                        }
                      }
                    }
                  }
                }
              }
            `,
          })
      
          if (res.data) {
            const schema = JSON.stringify(res.data)
            // Specify where the schema should be written to
            fs.writeFileSync(path.resolve(__dirname, '../../schema.json'), schema)
          } else {
            throw new Error('No Data')
          }
          process.exit()
        } catch (e) {
          console.log(e)
          process.exit(1)
        }
      }
      
      main()
      
      1. 将脚本包含在您的codegen.yml
      schema: "./schema.json"
      documents: ./src/**/*.graphql
      generates:
        ./src/generated.tsx:
          plugins:
            - typescript
            - typescript-operations
            - typescript-react-apollo
          config:
            withHooks: true
            withComponent: false
      hooks:
        afterStart:
          - ts-node  <path to script>/introspectPrismic.ts
      

      也许这不是最优雅的解决方案,但它确实有效!

      【讨论】:

      • 非常好的解决方案。如何在 Next.js 应用程序中使用 createApolloClient()
      • @Devz 见Next提供的例子。
      【解决方案3】:

      这有几个要素:

      • 请求必须使用GET
      • Prismic-ref 标头必须与master ref 的 ID 一起传递
      • 必须提供访问令牌(对于私有 API),即使对于自省也是如此

      Codegen 支持customFetch 选项,它允许我们自定义传出请求。我已将上述步骤打包成customFetch 实现并在此处发布:

      https://www.npmjs.com/package/codegen-prismic-fetch

      【讨论】:

        猜你喜欢
        • 2015-05-18
        • 2022-01-04
        • 2019-01-27
        • 2019-05-08
        • 2019-04-08
        • 2020-03-18
        • 2019-02-07
        • 2021-08-29
        • 2020-01-17
        相关资源
        最近更新 更多