Apollo Server + Next.js - GraphQL Schema 未更新

Posted

技术标签:

【中文标题】Apollo Server + Next.js - GraphQL Schema 未更新【英文标题】:Apollo Server + Next.js - GraphQL Schema Not Updating 【发布时间】:2021-03-03 06:30:01 【问题描述】:

我有一个 Apollo GraphQL / Next.js 应用程序。在更改我的 graphql 架构并导航到位于“http://localhost:3000/api/graphql”的 graphql 操场后,操场和我的应用程序中仍在引用旧的架构。

我尝试过清除节点模块并运行 npm install、清除缓存、重新启动所有内容,但我无法理解为什么我的架构没有更新。我错过了一些关键的架构更新步骤吗?

这是我的 Series 和 Publisher 架构(请注意,SeriesInput 需要 Publisher,而不是 PublisherInput):

type Series 
    _id: ID!
    name: String
    altID: String
    publisher: Publisher!
    comics: [Comic]


input SeriesInput 
    _id: ID
    name: String!
    altID: String
    publisher: Publisher!
    comics: [Comic]


type Mutation 
    addSeries(series: SeriesInput): Series


type Query 
    series: [Series]


-------------------------

type Publisher 
    _id: ID!
    name: String
    altID: String
    series: [Series]


input PublisherInput 
    _id: ID!
    name: String!
    altID: String
    series: [Series]


type Mutation 
    addPublisher(publisher: PublisherInput): Publisher


type Query 
    publishers: [Publisher]


Here 是我在 GraphQL Playground 中收到的错误消息,这是因为旧系列模式需要一个 PublisherInput 类型,该类型具有“名称”的必填字段,我没有通过。

这是我的 graphql apollo 服务器代码,我使用 mergeResolvers 和 mergeTypeDefs 将所有 graphql 文件合并到一个模式中:

import  ApolloServer  from "apollo-server-micro";
import  mergeResolvers, mergeTypeDefs  from "graphql-tools";
import connectDb from "../../lib/mongoose";

// Mutations and resolvers
import  comicsResolvers  from "../../api/comics/resolvers";
import  comicsMutations  from "../../api/comics/mutations";
import  seriesResolvers  from "../../api/series/resolvers";
import  seriesMutations  from "../../api/series/mutations";
import  publishersResolvers  from "../../api/publishers/resolvers";
import  publishersMutations  from "../../api/publishers/mutations";

// GraphQL Schema
import Publishers from "../../api/publishers/Publishers.graphql";
import Series from "../../api/series/Series.graphql";
import Comics from "../../api/comics/Comics.graphql";

// Merge type resolvers, mutations, and type definitions
const resolvers = mergeResolvers([
    publishersMutations,
    publishersResolvers,
    seriesMutations,
    seriesResolvers,
    comicsMutations,
    comicsResolvers,
]);
const typeDefs = mergeTypeDefs([Publishers, Series, Comics]);

// Create apollo server and connect db
const apolloServer = new ApolloServer( typeDefs, resolvers );
export const config = 
    api: 
        bodyParser: false,
    ,
;
const server = apolloServer.createHandler( path: "/api/graphql" );
export default connectDb(server);

这是我在 Vercel 文档中使用的 apollo/next.js 代码:

 * Code copied from Official Next.js documentation to work with Apollo.js
 * https://github.com/vercel/next.js/blob/6e77c071c7285ebe9998b56dbc1c76aaf67b6d2f/examples/with-apollo/lib/apollo.js
 */

import React,  useMemo  from "react";
import Head from "next/head";
import  ApolloProvider  from "@apollo/react-hooks";
import  ApolloClient  from "apollo-client";
import  InMemoryCache  from "apollo-cache-inmemory";
import  HttpLink  from "apollo-link-http";
import fetch from "isomorphic-unfetch";

let apolloClient = null;

/**
 * Creates and provides the apolloContext
 * to a next.js PageTree. Use it by wrapping
 * your PageComponent via HOC pattern.
 * @param Function|Class PageComponent
 * @param Object [config]
 * @param Boolean [config.s-s-r=true]
 */
export function withApollo(PageComponent,  s-s-r = true  = ) 
    const WithApollo = ( apolloClient, apolloState, ...pageProps ) => 
        const client = useMemo(() => apolloClient || initApolloClient(apolloState), []);
        return (
            <ApolloProvider client=client>
                <PageComponent ...pageProps />
            </ApolloProvider>
        );
    ;

    // Set the correct displayName in development
    if (process.env.NODE_ENV !== "production") 
        const displayName = PageComponent.displayName || PageComponent.name || "Component";

        if (displayName === "App") 
            console.warn("This withApollo HOC only works with PageComponents.");
        

        WithApollo.displayName = `withApollo($displayName)`;
    

    if (s-s-r || PageComponent.getInitialProps) 
        WithApollo.getInitialProps = async (ctx) => 
            const  AppTree  = ctx;

            // Initialize ApolloClient, add it to the ctx object so
            // we can use it in `PageComponent.getInitialProp`.
            const apolloClient = (ctx.apolloClient = initApolloClient());

            // Run wrapped getInitialProps methods
            let pageProps = ;
            if (PageComponent.getInitialProps) 
                pageProps = await PageComponent.getInitialProps(ctx);
            

            // Only on the server:
            if (typeof window === "undefined") 
                // When redirecting, the response is finished.
                // No point in continuing to render
                if (ctx.res && ctx.res.finished) 
                    return pageProps;
                

                // Only if s-s-r is enabled
                if (s-s-r) 
                    try 
                        // Run all GraphQL queries
                        const  getDataFromTree  = await import("@apollo/react-s-s-r");
                        await getDataFromTree(
                            <AppTree
                                pageProps=
                                    ...pageProps,
                                    apolloClient,
                                
                            />
                        );
                     catch (error) 
                        // Prevent Apollo Client GraphQL errors from crashing s-s-r.
                        // Handle them in components via the data.error prop:
                        // https://www.apollographql.com/docs/react/api/react-apollo.html#graphql-query-data-error
                        console.error("Error while running `getDataFromTree`", error);
                    

                    // getDataFromTree does not call componentWillUnmount
                    // head side effect therefore need to be cleared manually
                    Head.rewind();
                
            

            // Extract query data from the Apollo store
            const apolloState = apolloClient.cache.extract();

            return 
                ...pageProps,
                apolloState,
            ;
        ;
    

    return WithApollo;


/**
 * Always creates a new apollo client on the server
 * Creates or reuses apollo client in the browser.
 * @param  Object initialState
 */
function initApolloClient(initialState) 
    // Make sure to create a new client for every server-side request so that data
    // isn't shared between connections (which would be bad)
    if (typeof window === "undefined") 
        return createApolloClient(initialState);
    

    // Reuse client on the client-side
    if (!apolloClient) 
        apolloClient = createApolloClient(initialState);
    

    return apolloClient;


/**
 * Creates and configures the ApolloClient
 * @param  Object [initialState=]
 */
function createApolloClient(initialState = ) 
    // Check out https://github.com/zeit/next.js/pull/4611 if you want to use the AWSAppSyncClient
    return new ApolloClient(
        s-s-rMode: typeof window === "undefined", // Disables forceFetch on the server (so queries are only run once)
        link: new HttpLink(
            uri: "http://localhost:3000/api/graphql", // Server URL (must be absolute)
            credentials: "same-origin", // Additional fetch() options like `credentials` or `headers`
            fetch,
        ),
        cache: new InMemoryCache().restore(initialState),
    );

【问题讨论】:

【参考方案1】:

我遇到了同样的问题,原因是下一个 js 处理缓存的方式。删除.next文件夹,然后重启服务器,问题就解决了。

【讨论】:

【参考方案2】:

好吧,我花了将近 5 天的时间试图弄清楚我做错了什么,或者 Apollo 服务器是否正在缓存生产中的架构,以发现 Apollo 客户端源指向错误的服务器。

也许你也应该检查一下。

【讨论】:

如何检查?我不确定我是否熟悉手动设置详细信息,因为我刚刚使用了 create-next-app。 抱歉,看起来很好我可以看到我们的问题略有不同

以上是关于Apollo Server + Next.js - GraphQL Schema 未更新的主要内容,如果未能解决你的问题,请参考以下文章

无法在 Next.js 应用程序中使用 Apollo-client GraphQL 上传文件:缺少 POST 正文

Next.js/Next-Auth/Apollo/GraphQL 设置

next.js 中的 apollo-client 与 `next-with-apollo` VS next.js 文档常见问题解答中显示的方法(不使用 `getDataFromTree`)

apollo-server-micro:响应缺少标头“访问控制允许方法:POST”

使用 Next Js getServerSideProps 进行 Apollo 查询?

Next Js 自定义路由和 s-s-r