Apollo服务器多个第三方Apis

时间:2020-08-21 22:56:01

标签: api graphql next.js apollo apollo-server

考虑在Apollo服务器上使用下一个js和新的api路由。但是,我并没有使用一种数据源。我将使用内容丰富和购物的方式,但是可能会使用更多的第三方API。

您如何使用多个第三方API并通过自定义端点访问所有数据? 有例子吗?

1 个答案:

答案 0 :(得分:0)

您可以使用称为GraphQL模式拼接的技术将多个GraphQL API组合到一个统一的端点中。阿波罗有一个extensive guide on the topic

我还写了一个两部分的指南,介绍如何将Contentful API与其他API结合在一起:Part 1Part 2

所有这些示例都是围绕Apollo Server构建的,但是相同的方法也适用于Apollo Client。因此,您可以选择作为API的一部分进行拼接(将GraphQL API,Shopify和Contentful添加到统一端点)或在客户端进行拼接。这些都有优点和缺点。服务器端通常会减少来自客户端的请求,而客户端则会消除作为拼接代理的单点故障。

使用Apollo服务器的基本设置如下:

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查询。为此,您必须将字段缝合在一起。我建议您深入上面的链接,它们会更深入地解释这一点。