I am creating an app using DGraph that I am fronting with a GraphQL server using the Apollo server libraries.
So far what I have been doing is creating the DGraph schema and matching it to a GraphQL schema.
Question: Does anyone on this forum have an elegant solution for limiting the selected predicates (model properties) for the DGraph GraphQL± query inside a GraphQL server request?
Example I want to get “AvailabilityBlocks” which has numerous properties and sub properties, however for some GraphQL requests I only want to get “version” and “startDate”. To be clear this currently works as the GraphQL server will throw away all the unneeded attributes, it just feels inefficient to ask DGraph to get all these attributes just to throw some of them away.
Potential solutions and pros/cons:
- More GraphQL endpoints that are backed by smaller DGraph queries.
- Not sure if this is good or bad practice for GraphQL endpoints. Feels like the api is then just going back to being a REST server.
- Use an NPM module like graphql-list-fields an write a function to construct the DGraph GraphQL± query from the GraphQL query.
- This is the path that appeals to me the most, here I would trade off server time parsing and constructing the query, against being inefficient by asking DGraph for more data than I need.
- Wait until DGraph supports GraphQL and I could just pass the query along.
- I am not sure exactly what the team has planed for GraphQL. Also I feel like I will still want some sort of custom GraphQL endpoint to validate the users permissions in front of the DB. I may want to add query validations / white lists. Passing raw queries to a DB from a client is bad practice. So this solution may need a shim still anyway.
Has anyone else come up against this issue? Maybe it’s not an issue, as it is, DGraph might be so efficient that throwing away those extra fields is the solution.
Anyway any comments / thoughts would be appreciated.
Sample code for more context:
GraphQL Full Query
{
availabilityBlocks(username: "foo") {
uid
version
startDate
active
repeatFrequency
weeks {
uid
weekName
availabilityDays {
uid
dayName
availabilityTimes {
uid
from
to
contactMethods {
uid
contactMethodName
contactMethodKey
}
}
}
}
}
}
GraphQL Limited Query
{
availabilityBlocks(username: "foo") {
uid
version
startDate
}
}
GraphQL Schema
const AvailabilityBlock = `
enum RepeatFrequency {
WEEKLY
FORTNIGHTLY
}
type AvailabilityTimes {
uid: String
from: Int!
to: Int!
contactMethods: [ContactMethod]
}
type ContactMethod {
uid: String
contactMethodName: String!
contactMethodKey: String!
}
type AvailabilityDay {
uid: String
dayName: String
availabilityTimes: [AvailabilityTimes]
}
type Week {
uid: String
weekName: String
availabilityDays: [AvailabilityDay]
}
type AvailabilityBlock {
uid: String
version: Int!
startDate: Int!
active: Boolean!
repeatFrequency: RepeatFrequency!
weeks: [Week]
}
`;
export default [AvailabilityBlock]
Resolver function calling DGraph with large query
import {newDgraphClient} from '../../dgraph';
// ** THIS IS THE DGRAPH+- QUERY THAT SHOULD BE LIMITED **
function query(username: string) {
return `query {
userAvailabilityBlocks(func: eq(username, ${username}))
{
uid
availabilityBlocks {
uid
version
startDate
active
repeatFrequency
weeks {
uid
weekName
availabilityDays {
uid
dayName
availabilityTimes {
uid
from
to
contactMethods {
uid
contactMethodName
contactMethodKey
}
}
}
}
activatedHistory
deactivatedHistory
}
}
}`;
}
export async function availabilityBlocksResolver(
_: any,
{username}: any,
context: any,
info: any,
dgraph = newDgraphClient()
) {
const {dgraphClient, dgraphClientStub} = dgraph;
const constructedQuery = query(username);
let result = null;
const txn = dgraphClient.newTxn();
try {
const res = await txn.query(constructedQuery);
const jsonStr = new Buffer(res.getJson_asU8()).toString();
result = JSON.parse(jsonStr).userAvailabilityBlocks[0].availabilityBlocks;
} catch(e) {
console.log('availabilityBlocksError', e)
}
dgraphClientStub.close();
return result
}