GraphQL +- to GraphQL shim

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
}

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.