graphile / federation Goto Github PK
View Code? Open in Web Editor NEWApollo federation support for PostGraphile [UNMAINTAINED]
License: MIT License
Apollo federation support for PostGraphile [UNMAINTAINED]
License: MIT License
Hello guys,
I'm trying to federate two postgraphile endpoints with the Apollo Federation gateway but can't seem to find a working combination.
Given I started the postgraphile endpoints with Federation support (using FederationPlugin) and Relay support (default NodePlugin activated), when I start the Apollo Federation gateway, it complains with the following error:
(node:19865) UnhandledPromiseRejectionWarning: GraphQLSchemaValidationError: Field "Query.query" can only be defined once.
Field "Query.nodeId" can only be defined once.
Field "Query.node" can only be defined once.
at ApolloGateway.createSchema (/home/cvidal/Documents/Sources/pocs/postgraphile/federation/node_modules/@apollo/gateway/dist/index.js:210:19)
at ApolloGateway.<anonymous> (/home/cvidal/Documents/Sources/pocs/postgraphile/federation/node_modules/@apollo/gateway/dist/index.js:181:32)
at Generator.next (<anonymous>)
at fulfilled (/home/cvidal/Documents/Sources/pocs/postgraphile/federation/node_modules/@apollo/gateway/dist/index.js:5:58)
at Object.dynatraceRegularInvoke [as doInvoke] (/opt/dynatrace/oneagent/agent/res/nodeagent/nodejsagent.js:1732:20)
at Object.a.safeInvoke (/opt/dynatrace/oneagent/agent/res/nodeagent/nodejsagent.js:1802:29)
at /opt/dynatrace/oneagent/agent/res/nodeagent/nodejsagent.js:6952:25
at processTicksAndRejections (internal/process/task_queues.js:93:5)
I investigated a bit and looking at the Apollo Federation demo here https://github.com/apollographql/federation-demo, the federated services don't expose node and nodeId fields in the Query type.
I therefore tested starting the two postgraphile endpoints without Relay support (skipping the NodePlugin
plugin) but the FederationPlugin
plugin fails with :
Error: Union type _Entity must define one or more member types.
at assertValidSchema (/home/cvidal/Documents/Sources/pocs/postgraphile/custom-postgraphile/node_modules/graphql/type/validate.js:71:11)
at Object.validate (/home/cvidal/Documents/Sources/pocs/postgraphile/custom-postgraphile/node_modules/graphql/validation/validate.js:54:35)
at parseQuery (/home/cvidal/Documents/Sources/pocs/postgraphile/custom-postgraphile/node_modules/postgraphile/src/postgraphile/http/createPostGraphileHttpRequestHandler.ts:352:32)
at /home/cvidal/Documents/Sources/pocs/postgraphile/custom-postgraphile/node_modules/postgraphile/src/postgraphile/http/createPostGraphileHttpRequestHandler.ts:690:55
at Array.map (<anonymous>)
at requestHandler (/home/cvidal/Documents/Sources/pocs/postgraphile/custom-postgraphile/node_modules/postgraphile/src/postgraphile/http/createPostGraphileHttpRequestHandler.ts:650:20)
at processTicksAndRejections (internal/process/task_queues.js:93:5)
Apparently, this is a known problem in Apollo Federation that Relay is not supported:
https://spectrum.chat/apollo/apollo-federation/federation-with-relays-node-interface~c0ae3cb1-d243-491a-ac58-17307629e31e
So, this problem may be spread between Postgraphile and Apollo Federation Gateway.
That being said, I can't find a working combination so far, with or without Relay support.
When using Graphile federated with another service, it seems to make more sense for the key to be on the primary keys of the resource instead of the nodeId
. This is because any other resource would be likely to have access to the resource by its primary keys.
This can be worked around by adding @requires(fields: {primary keys})
to each other field and fetching by the keys in __resolveReference
but this seemed like a bad solution.
We are looking at using postgraphile for a new project with part of the decision based on its compatibility with Apollo Federation or the latest GraphQL Tools Schema Stitching. I set up a boiler plate project with postgraphile and a local Apollo server and found that this plugin did not work as expected with the latest versions of federation. I then stumbled on a fork of this repo from last year https://github.com/jarvisuser90/postgraphile-apollo-federation-plugin which got me further but also needed a few changes. I opened a PR to that repo at brooklyn-labs/postgraphile-plugin-apollo-federation#11.
Unfortunately, I don't think the maintainer of the fork as an active user anymore which puts me in an odd place. I would prefer to get those changes, and possibly the diff in the fork, into this repository instead, but I have feeling the fork was created due to changes not being merged here in a timely manner.
Does anyone know the current status of this plugin? Would it be better to fork again and keep things moving or would pull requests to this repo be looked at versus left to go stale?
I would much prefer to keep things here as this feels like this most official place for the plugin to thrive, but I am unsure how the activeness.
Thanks for the information!
I would like to add a schema extension plugin in this nodejs Postgraphile server to pointing to another type in another GraghQL service. The other service is running with Apollo Server. Then would like to register both GrqphQL with Apollo Gateway.
However, in my plugin:
const { makeExtendSchemaPlugin, gql } = require("graphile-utils");
const SchemaExtensionPlugin = makeExtendSchemaPlugin(build => {
// Get any helpers we need from `build`
const { pgSql: sql, inflection } = build;
return {
typeDefs: gql`
extend type Query {
ThingLinked: [ThingLinkedProduct]
}
type ThingLinkedProduct @key(fields: "id") {
id: Int!
name: String
product: Product
}
extend type Product @key(fields: "upc") {
upc: String! @external
}
`,
resolvers: {...}
};
});
export default SchemaExtensionPlugin;
Error:
Error: Could not find type named 'Product'.
at getType (C:\Workspace\EMCP\node_modules\graphile-utils\src\makeExtendSchemaPlugin.ts:516:15)
at C:\Workspace\EMCP\node_modules\graphile-utils\src\makeExtendSchemaPlugin.ts:755:24
I even tried to add Apollo's buildFederatedSchema API in this extension, got different error.
Is this feature supported?
I'm able to add 'extend type' the other way around. Added 'extend type' from here to the other Apollo Server GraphQL, and Apollo gateway can query this one using nodeId
I have two example PostGraphile services: a media service having a movie
entity and a video service having a video
entity. The movie entity stores the ID of the video. The federation service should allow to query movie->video->title.
Using latest PostGraphile in library version and latest version of the graphile/federation library.
I am using the express way to include PostGraphile in the minimal version for each service.
I am following the guide on https://www.apollographql.com/docs/federation/quickstart/ to add both services to the federation service. This works all fine - I can get in one query both the details from the media and video service (but cannot resolve movie --> video --> fields).
CREATE TABLE public.movies (
id INT NOT NULL PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY,
title text NOT NULL,
description text,
video_id INT
);
INSERT INTO public.movies (title, description, video_id) VALUES
('Avatar', 'Jake, who is paraplegic, replaces his twin on the Na''vi inhabited Pandora for a corporate mission. After the natives accept him as one of their own, he must decide where his loyalties lie.', 1),
('Black Widow', 'Natasha Romanoff, aka Black Widow, confronts the darker parts of her ledger when a dangerous conspiracy with ties to her past arises. Pursued by a force that will stop at nothing to bring her down, Natasha must deal with her history as a spy, and the broken relationships left in her wake long before she became an Avenger.', 2),
('The Lord of the Rings: The Two Towers', 'Frodo and Sam arrive in Mordor with the help of Gollum. A number of new allies join their former companions to defend Isengard as Saruman launches an assault from his domain.', 3);
CREATE TABLE public.videos (
id INT NOT NULL PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY,
title text NOT NULL,
video_url text
);
INSERT INTO public.videos (id, title, video_url) VALUES
(1, 'Avatar Trailer', 'https://www.youtube.com/watch?v=6ziBFh3V1aM'),
(2, 'Black Widow Trailer', 'https://www.youtube.com/watch?v=ybji16u608U'),
(3, 'The Lord of the Rings: The Two Towers Trailer', 'https://www.youtube.com/watch?v=Y4neBR0h39c');
The _entities
query is working nicely when I run it directly against the video service.
query videos {
_entities(representations: [
{
__typename: "Video",
nodeId: "WyJ2aWRlb3MiLDFd"
}]) {
... on Video {
id
nodeId
title
videoUrl
}
}
}
I tried multiple different approaches with makeExtendSchemaPlugin
and others - how can I correctly update the Movie
entity to have a Video
reference?
In the end I (think I) need the following in the generated schema:
type Movie implements Node @key(fields: "nodeId") {
id: Int!
title: String!
description: String
nodeId: ID!
videoId: Int
# this video here - should be resolved via nodeId (or directly the ID if that is possible)
video: Video
}
extend type Video @key(fields: "nodeId") {
nodeId: ID! @external
}
My failed attempt with a plugin on the media side:
const { makeExtendSchemaPlugin, gql } = require("graphile-utils");
const ExtendPlugin = makeExtendSchemaPlugin(() => {
return {
typeDefs: gql`
# hack - must be later removed
type Video {
DoNotUseThisProperty: String
}
# This is how it should really look like - or use the nodeId:
extend type Video @key(fields: "id") {
id: Int! @external
}
extend type Movie {
video: Video
}
`,
resolvers: {
Movie: {
video: async (movie) => {
console.log(movie);
return {
id: movie.videoId,
};
},
},
},
};
});
module.exports = ExtendPlugin;
With the above plugin the video service does not correctly receive any request to resolve the video
entity within the video service.
The following query against the federation service would be my goal - the allVideos
is working fine and allMovies
is working fine if I remove the video
sub-object query:
query ExampleQuery {
allMovies {
nodes {
id
videoId
title
video {
id
title
nodeId
}
}
}
allVideos {
nodes {
id
title
videoUrl
}
}
}
Thanks for any suggestions or ideas.
Will this plugin be maintained again once v5 of Posgraphile is released?
Using types from other service just does not work. I can't define external derectives properly, and get errors about must being used with @requires, @provides, or as a key type. I cannot get it to work. Let me link you to the thread of discussion
and the discussion on graphile discord which resulted in no solution:
I have a question about how federation is supposed to work. I have postgraphile setup and working and can see my schema. Now in another service i want to have a mutation that returns one of the types made from the postgraphile service. Let's call this type 'User' and the user has some nested fields one of which is 'UUID'. When i try to reference this type apollo complains about unknown type. The only way i can fix this is if i extend the type and basically redefine every field and add @key and @external directives. This seems pointless to use federation if i have to redefine the types i want to share in every new service?? What am i misunderstanding?
extend type User @key(fields: "nodeId") {
id: UUID! @external
name: String! @external
position: String! @external}
this is the type i want to share. I extend it like that in the service i want to use it from, but it's made by postgraphile itself
i'm trying to use it like this
type Mutation { doaThing(blah: String) : User @external }
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.