【发布时间】:2020-12-11 07:40:11
【问题描述】:
着眼于在 Apollo 服务器上使用 next js 和新的 api 路由。但是,我没有使用一种数据源。我将使用 contentful 和 shopify,但可能会使用更多的 3rd 方 API。
您如何使用多个第 3 方 API 并通过自定义端点访问所有数据? 有什么例子吗?
【问题讨论】:
标签: api graphql next.js apollo apollo-server
着眼于在 Apollo 服务器上使用 next js 和新的 api 路由。但是,我没有使用一种数据源。我将使用 contentful 和 shopify,但可能会使用更多的 3rd 方 API。
您如何使用多个第 3 方 API 并通过自定义端点访问所有数据? 有什么例子吗?
【问题讨论】:
标签: api graphql next.js apollo apollo-server
您可以使用称为 GraphQL 模式拼接的技术将多个 GraphQL API 组合成一个统一的端点。阿波罗有一个extensive guide on the topic。
我还编写了两部分指南,如何将 Contentful API 与其他 API 拼接在一起:Part 1、Part 2。
所有这些示例都是围绕 Apollo Server 构建的,但同样的方法也适用于 Apollo Client。因此,您可以选择将拼接作为 API 的一部分(将 GraphQL API、Shopify 和 Contentful 添加到统一端点)或在客户端进行拼接。这些都有优点和缺点。服务器端通常会减少从客户端发出的请求,而客户端会消除作为拼接代理的单点故障。
使用 Apollo Server 的基本设置如下:
const {ApolloServer} = require('apollo-server');
const {HttpLink} = require('apollo-link-http');
const {setContext} = require('apollo-link-context');
const {
introspectSchema,
makeRemoteExecutableSchema,
mergeSchemas
} = require('graphql-tools');
const fetch = require('node-fetch');
const {GITHUB_TOKEN, CONTENTFUL_SPACE, CONTENTFUL_TOKEN} = require('./config.json');
const gitHubLink = setContext((request) => ({
headers: {
'Authorization': `Bearer ${GITHUB_TOKEN}`,
}
})).concat(new HttpLink({uri: 'https://api.github.com/graphql', fetch}));
const contentfulLink = setContext((request) => ({
headers: {
'Authorization': `Bearer ${CONTENTFUL_TOKEN}`,
}
})).concat(new HttpLink({uri: `https://graphql.contentful.com/content/v1/spaces/${CONTENTFUL_SPACE}`, fetch}));
async function startServer() {
const gitHubRemoteSchema = await introspectSchema(gitHubLink);
const gitHubSchema = makeRemoteExecutableSchema({
schema: gitHubRemoteSchema,
link: gitHubLink,
});
const contentfulRemoteSchema = await introspectSchema(contentfulLink);
const contentfulSchema = makeRemoteExecutableSchema({
schema: contentfulRemoteSchema,
link: contentfulLink,
});
const schema = mergeSchemas({
schemas: [
gitHubSchema,
contentfulSchema
]
});
const server = new ApolloServer({schema});
return await server.listen();
}
startServer().then(({ url }) => {
console.log(`? Server ready at ${url}`);
});
请注意,这只会合并两个 GraphQL 模式。如果两个 API 的类型或根字段名称相同,您可能会发生冲突。
两个确保您没有任何冲突我建议您转换所有模式以赋予类型和根字段唯一的前缀。这可能看起来像这样:
async function getContentfulSchema() {
const contentfulRemoteSchema = await introspectSchema(contentfulLink);
const contentfulSchema = makeRemoteExecutableSchema({
schema: contentfulRemoteSchema,
link: contentfulLink,
});
return transformSchema(contentfulSchema, [
new RenameTypes((name) => {
if (name.includes('Repository')) {
return name.replace('Repository', 'RepositoryMetadata');
}
return name;
}),
new RenameRootFields((operation, fieldName) => {
if (fieldName.includes('repository')) {
return fieldName.replace('repository', 'repositoryMetadata');
}
return fieldName;
})
]);
}
这将让您以统一的方式使用所有 API,但您无法跨不同的 API 进行查询。为此,您必须将字段拼接在一起。我建议您深入了解上面的链接,他们对此进行了更深入的解释。
【讨论】:
graphql-transform-federation。正如最初设计的那样,Federation 并不是真正将第 3 方 API 缝合在一起。这种转换可能是一个有趣的解决方案。 GraphQL Mesh 很早。我确实想知道所有这些动态配置的开销最终会是多少。