Hi!
I know this is a little old but I found a (admittedly very questionable) workaround for Assumption 1 (also part of the GraphQL specs) that a server must provide a root field called node
which returns an interface Node
. Doing this, will check 1 and 3 of the Relay compliance and pagination can also be done via first/next.
At first we have to add the Node
interface to our schema and define a custom lambda resolver called node
.
Node interface
interface Node @generate(
query: {
get: true,
query: false,
aggregate: false
},
mutation: {
add: false,
delete: false
},
subscription: false
) {
id: ID!
}
I have disabled the generation of all queries/mutations apart from getNode
.
Apply to a type
type Test implements Node {
name: String
...
}
Apply the Node
interface to any type you wish to query via node
(@refetchable will work when using Relay).
Set up lambda
type Query {
node(id: ID!): Node @lambda
}
So far so good, we have set all up but unfortunately the query node
will not work since we would have to implement all possible query solutions which is offered by getNode
. In order to do so I alter the id string of the input parameter and attach the query which gets generated by Relay (I know this is …).
I use react-relay-network-modern
for setting up the Relay environment but it should work with the standard implementation as well. So when defining my network, I do:
const network = new RelayNetworkLayer([
cacheMiddleware({
size: 100, // max 100 requests
ttl: 900000, // 15 minutes
}),
urlMiddleware({
url: (req) => Promise.resolve(GRAPHQL_ENDPOINT),
}),
(next) => async (req) => {
let queryBody = {
query: req.getQueryString(),
variables: req.getVariables(),
};
// THIS IS WHERE THE CRAZY HAPPENS
if ( queryBody.query.includes('node(id: $id)') ) {
queryBody.variables.id = queryBody.variables.id + '_QUERY_' + queryBody.query;
}
req.fetchOpts.body = JSON.stringify(queryBody);
const res = await next(req);
return res;
},
]);
In the lambda I can now parse the string, replace node(id: $id)
with getNode(id: $id)
and run the query.
The lambda
export const getNode = async ({ args, graphql }) => {
const { id } = args;
const queryBody = id.split('_QUERY_');
const queryId = queryBody[0];
const query = query[1].replace('node(id: $id)', 'getNode(id: $id)');
const res = await this.graphql( query, { id: queryId });
return res.data.getNode;
}
I know this is a horrendous workaround but it works and lets me do @refetchables
as well. I guess it would not be a major task for the Dgraph Team to automatically add the Node Interface and rename the getNode query to node
. We would still have to implement Node
to every type we would need to have access but that’s ok I guess.
Let me know what you think!