Skip to content

Instantly share code, notes, and snippets.

@JoeKarlsson
Last active January 1, 2023 19:33
Show Gist options
  • Star 14 You must be signed in to star a gist
  • Fork 4 You must be signed in to fork a gist
  • Save JoeKarlsson/ca1d2f3e95fa2412feb418aedfbf9844 to your computer and use it in GitHub Desktop.
Save JoeKarlsson/ca1d2f3e95fa2412feb418aedfbf9844 to your computer and use it in GitHub Desktop.
graphql + dataloader + express-graphql Live Coding Demo

How to test if Dataloader is working correctly, we are going to turn on server logging in order to see how many queries are being made to our db. If Dataloader is setup correctly, we should only see one hit on our db perrequest, even if duplicate data is being requested. Here's how to enable logging on postgresql. Note - This is the Mac way to enable logging.

  • subl /usr/local/var/postgres/postgresql.conf

  • around line 434 log_statement = 'all' uncomment and set to all log_statement = 'all'

  • then brew service restart postgresql

  • To view your logs coming in run tail -f /usr/local/var/postgres/server.log

  • Here is a sample graphiql query to test dataloader: { people { first_name spouse { fullName spouse { fullName spouse { fullName } } } } }

  • If Dataloader is setup correctly - you should only see one request being sent to your DB for multeiple calls.

const humps = require('humps');
module.exports = (pool) => ({
getUsersByIds(userIds) {
return pool.query(`
select id, first_name, last_name, email, spouse_id,
'Person' as type
from people
where id = ANY($1)
`, [userIds]).then(result => result.rows);
},
getUsers() {
return pool.query(`
select * from people
`).then(result => result.rows);
}
});
const express = require('express');
const graphqlHTTP = require('express-graphql')
const app = express();
const PORT = process.env.PORT || 3000;
// function, the actual executor of the schema
const { graphql } = require('graphql');
const pg = require('pg');
const pool = new pg.Pool({
database: 'graphql_server_db',
user: 'joecarlson'
});
const db = require('./database')(pool);
const DataLoader = require('dataloader');
// the schema to execute
const mySchema = require('./schema');
app.use('/graphql', (req, res) => {
const loaders = {
usersByIds: new DataLoader(db.getUsersByIds)
};
return graphqlHTTP({
schema: mySchema,
graphiql: true,
context: { pool, loaders }, // available to all graphql resolve as the third argument
})(req, res);
});
app.listen(PORT);
const {
GraphQLSchema,
GraphQLObjectType,
GraphQLString,
GraphQLInt,
GraphQLList,
GraphQLID,
GraphQLNonNull
} = require('graphql');
const humps = require('humps');
const db = require('./database');
const PersonType = new GraphQLObjectType({
name: 'Person',
fields: () => ({
id: { type: GraphQLID },
first_name: { type: GraphQLString },
last_name: { type: GraphQLString },
email: { type: GraphQLString },
spouse_id: { type: GraphQLInt },
fullName: {
type: GraphQLString,
resolve: obj => `${obj.first_name} ${obj.last_name}`
},
spouse: {
type: PersonType,
resolve: ( obj, args, { loaders }, info ) => loaders.usersByIds.load(obj.spouse_id)
}
})
});
const queryType = new GraphQLObjectType({
name: 'RootQuery',
fields: {
person: {
type: PersonType,
args: {
id: {
type: new GraphQLNonNull(GraphQLInt)
}
},
// 4th is execution context ----v
resolve: ( obj, args, { loaders }, info ) => loaders.usersByIds.load(args.id)
},
people: {
type: new GraphQLList(PersonType),
resolve: ( obj, args, { pool } ) => db(pool).getUsers()
}
}
});
const mySchema = new GraphQLSchema({
query: queryType,
// mutation: mutationType
});
module.exports = mySchema;
@ilearnio
Copy link

ilearnio commented Jun 6, 2018

As far as I see, the same loaders object is going to be reused between requests without ever cleaning it's cache. Would be good if it would use the cache per request only, and would do requests to DB for every request

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment