I use this awesome project + graphiql to provide extended interface for admins. It's completely what we need, but it's a little bit tricky to mask some sensitive fields in responses like that:

I implement this by using low-level interface functions createPostGraphQLSchema and withPostGraphQLContext. It's ok, but I have lot's of project's and don't want to copy-paste this solution, instead, it will be great to extend postgraphql, and pass custom handler in it.
I think it will be really useful for lot's of users, sincepostgraphql function has super-friendly interface, works as middleware for express and can be combined with other middlewares to pre-process request, so I offer to add ability for post-process response.
I think I can implement it and submit pr, but first I need to make sure if authors not mind to include this functionality.
Do you mind sharing your current solution? If you don't want to divulge publicly you can DM me a private gist on gitter?
@benjie no problem, it's pretty trivial and based on this library documentation.
This is definition of my middleware, execGraphQL
const Pool = require('pg-pool')
const { graphql } = require('graphql')
const { createPostGraphQLSchema, withPostGraphQLContext } = require('postgraphql')
const { copyWithoutSecrets } = require('../services/util')
const pgOpts = {
...
}
const pgPool = new Pool(pgOpts)
const createSchema = createPostGraphQLSchema(pgOpts)
module.exports = function(req, res) {
return createSchema.then(schema => {
const cb = context => graphql(
schema,
req.body.query,
null,
req.body.context,
req.body.variables,
operationName
)
return withPostGraphQLContext({pgPool}, cb)
})
.then(copyWithoutSecrets) // Process result with custom handler
.then(processedResult => res.json(processedResult))
}
And this is how I use it:
app.post('/admin/graphql', checkAdminPermissions, execGraphQL)
So, I want to use postgraphql middleware like that:
app.post('/admin/graphql', checkAdminPermissions, postgraphql({resultHandler: copyWithoutSecrets}))
Or
app.post('/admin/graphql', checkAdminPermissions, postgraphql(), copyWithoutSecretsMiddleware)
Thanks for sharing, that makes it a lot clearer what you're intending. I'm happy this solution works for you, but I don't think we want this specific solution in PostGraphQL core - the correct way to do it would be to replace the resolver for those fields within the generated GraphQL schema itself. I'm not sure off-hand how you'd go about doing that (it would most likely require changes to PostGraphQL?). If you wanted to experiment around that functionality (modifying the generated schema, e.g. by revealing some hooks the user can use to tweak how the resolvers are generated) then a proof-of-concept for us to analyse would be very welcome!
@benjie yeah, I noticed that project ideology in providing a schema-driven development, but why you think the correct way is internal changes for allow replacing resolvers? It will be much more easy to implement and flexible for users if you allow to use postgraphql() as non-final resolver in middlewares chain. Currently it's impossible because its calling res.end(). So, if you provide some option to pass next() inside, and call it instead - users will be able to put any custom handlers after postgraphiql(). I think other users can use it for logging execution results, extend it with any data, transform to different format (maybe even render html templates), performance measurement, error handling, etc.
I was thinking along the lines of a wrapResolver hook, so that the current resolvers would be wrapped via; e.g. the following pseudocode:
postgraphql({
...
wrapResolvers: (resolver, {meta, ...}) => {
if (meta.type === 'field' && meta.schemaName === 'foo' && meta.tableName === 'teams' && meta.columnName === 'token') {
return () => '<Masked>';
} else if (...) {
return (...args) => {
const result = resolver.apply(this, args);
return convertBinaryToHex(result);
};
} else {
return resolver;
}
},
});
I think this is a much more natural interface than browsing the result data after the fact because it doesn't add any overhead to requests that don't use those fields and it doesn't require you to parse the query to know which fields are being used so that you can mask the relevant ones.
Does your current solution work for this query:
{
fred: teamById(id: "T1FQ72AAF") {
actuallyId: id
id: token
}
}
or does the token come back unmasked in the 'fred.id' field?
Would this be fixed if we had proper support for column level selection grants? For instance in Postgres you could run the following:
-- But not `col4`!
grant select (col1, col2, col3, col5) on table1 to role1;
鈥nd the user would get an error when trying to select col4.
@benjie you right, for my case this solution not work. Thank's for this query sample! I'm still think proposed functionality will improve that project, it's really general feature, e.g here the same thing: graphql/express-graphql#36. But, it looks like postgraphql
is not very suitable for my case, and I need something else (mb this one https://github.com/mickhansen/graphql-sequelize ?) so feel free to close this issue.
@SDSWanderer Another alternative could be to create and query a view instead. I'm going to close the issue for now, but feel free to continue discussing it and we may re-open if there is more demand for a feature like this.