我想联合服务,但让联合网关也拥有自己的架构和逻辑,以简化代理,它们可以代理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网关中保留自己的架构和逻辑?
答案 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}`);
});
})();