是否可以使用部分联邦网关?

时间:2019-08-01 08:17:26

标签: graphql apollo apollo-server federation

我想联合服务,但让联合网关也拥有自己的架构和逻辑,以简化代理,它们可以代理REST API端点。现在看来,我需要分别拥有联合网关服务,联合graphql服务和其余的<-> graphql网桥服务。无论如何,在其余情况下,rest-graphql网关至少可以暂时驻留在联合网关中,以避免不必要的引导和维护。

看起来像Apollo联合网关具有localServiceList似乎完全可以满足此目的。配置示例:

const gateway = new ApolloGateway({
    serviceList: [
        { name: "some-service", url: "http://localhost:40001/graph" }
    ],
    localServiceList: [
        { name: "rest-bridge", typeDefs }
    ]
});

但是并不能解决问题:如果存在localServiceList,它将跳过serviceList。

所以问题是:是否可以在Apollo Federation网关中保留自己的架构和逻辑?

2 个答案:

答案 0 :(得分:3)

是的,可以这样做:

import { buildFederatedSchema } from '@apollo/federation';
import {
  ApolloGateway,
  LocalGraphQLDataSource,
  RemoteGraphQLDataSource
} from '@apollo/gateway';
import gql from 'graphql-tag';

const localServices = {
  foo: {
    schema: {
      typeDefs: gql`
        // ...
      `,
      resolvers: {
        // ...
      }
    }
  },
  bar: {
    schema: {
      typeDefs: gql`
        // ...
      `,
      resolvers: {
        // ...
      }
    }
  }
};

const remoteServices = {
  baz: {
    url: 'http://baz.local/graphql'
  },
  qux: {
    url: 'http://qux.local/graphql'
  }
};

const services = {
  ...localServices,
  ...remoteServices
};

// By providing a protocol we trick ApolloGateway into thinking that this is a valid URL;
// otherwise it assumes it's a relative URL, and complains.
const DUMMY_SERVICE_URL = 'https://';

const gateway = new ApolloGateway({
  // We can't use localServiceList and serviceList at the same time,
  // so we pretend the local services are remote, but point the ApolloGateway
  // at LocalGraphQLDataSources instead...
  serviceList: Object.keys(services).map(name => ({
    name,
    url: services[name].url || DUMMY_SERVICE_URL
  })),
  buildService({ name, url }) {
    if (url === DUMMY_SERVICE_URL) {
      return new LocalGraphQLDataSource(
        buildFederatedSchema(
          services[name].schema
        )
      );
    } else {
      return new RemoteGraphQLDataSource({
        url
      });
    }
  }
});

const apolloServer = new ApolloServer({
  gateway,
  subscriptions: false
});

答案 1 :(得分:0)

我试图弄清楚同一件事。 @Ville解决了吗?我的示例尝试将本地的typeDefs和解析器与联合的解析器合并

const { ApolloServer, gql } = require("apollo-server");
const { ApolloGateway } = require("@apollo/gateway");
const { makeExecutableSchema } = require("graphql-tools");

const typeDefs = gql`
  type Query {
    getPerson(id: Int!): Person
    getFilm(id: Int!): Film
  }

  type Film {
    title: String
    episode_id: Int
    opening_crawl: String
    director: String
    characters: [Person]
  }
  type Person {
    name: String
    height: String
    gender: String
    films: [Film]
  }
`;

const resolvers = {
  Film: {},
  Person: {},
  Query: {
    getPerson: async (_, { id }, ctx, info) => {
      const response = await fetch(`https://swapi.co/api/people/${id}/`);
      return response.json();
    },
    getFilm: async (_, { id }, context, info) => {
      const response = await fetch(`https://swapi.co/api/films/${id}/`);
      return response.json();
    },
  },
};

const localSchema = makeExecutableSchema({
  typeDefs,
  resolvers,
});

const gateway = new ApolloGateway({
  serviceList: [
    { name: "accounts", url: "http://localhost:4001/graphql" },
    { name: "reviews", url: "http://localhost:4002/graphql" },
    { name: "products", url: "http://localhost:4003/graphql" },
    { name: "inventory", url: "http://localhost:4004/graphql" },
  ],
});

(async () => {
  const { schema, executor } = await gateway.load();

  const server = new ApolloServer({ schema, executor });

  server.listen().then(({ url }) => {
    console.log(`? Server ready at ${url}`);
  });
})();