Apollo 服务器 + Next.js - GraphQL 模式未更新
Apollo Server + Next.js - GraphQL Schema Not Updating
我有一个 Apollo GraphQL / Next.js 应用程序。在更改我的 graphql 架构并导航到位于“http://localhost:3000/api/graphql”的 graphql playground 之后,旧架构仍在 playground 和我的应用程序中被引用。
我已经尝试清除节点模块和 运行 npm 安装、清除缓存、重新启动所有内容,但我无法理解为什么我的模式没有更新。我是否遗漏了一些关键的架构更新步骤?
这是我的 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.ssr=true]
*/
export function withApollo(PageComponent, { ssr = 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 (ssr || 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 ssr is enabled
if (ssr) {
try {
// Run all GraphQL queries
const { getDataFromTree } = await import("@apollo/react-ssr");
await getDataFromTree(
<AppTree
pageProps={{
...pageProps,
apolloClient,
}}
/>
);
} catch (error) {
// Prevent Apollo Client GraphQL errors from crashing SSR.
// 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({
ssrMode: 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),
});
}
好吧,我花了将近 5 天的时间试图弄清楚我做错了什么,或者 Apollo 服务器是否正在缓存生产模式,以发现 Apollo 客户端源指向错误的服务器。
也许你也应该检查一下。
我 运行 遇到了同样的问题,发生这种情况的原因是下一个 js 处理缓存的方式。删除 .next
文件夹,然后重新启动服务器,即可解决问题。
我有一个 Apollo GraphQL / Next.js 应用程序。在更改我的 graphql 架构并导航到位于“http://localhost:3000/api/graphql”的 graphql playground 之后,旧架构仍在 playground 和我的应用程序中被引用。
我已经尝试清除节点模块和 运行 npm 安装、清除缓存、重新启动所有内容,但我无法理解为什么我的模式没有更新。我是否遗漏了一些关键的架构更新步骤?
这是我的 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.ssr=true]
*/
export function withApollo(PageComponent, { ssr = 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 (ssr || 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 ssr is enabled
if (ssr) {
try {
// Run all GraphQL queries
const { getDataFromTree } = await import("@apollo/react-ssr");
await getDataFromTree(
<AppTree
pageProps={{
...pageProps,
apolloClient,
}}
/>
);
} catch (error) {
// Prevent Apollo Client GraphQL errors from crashing SSR.
// 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({
ssrMode: 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),
});
}
好吧,我花了将近 5 天的时间试图弄清楚我做错了什么,或者 Apollo 服务器是否正在缓存生产模式,以发现 Apollo 客户端源指向错误的服务器。
也许你也应该检查一下。
我 运行 遇到了同样的问题,发生这种情况的原因是下一个 js 处理缓存的方式。删除 .next
文件夹,然后重新启动服务器,即可解决问题。