question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

[Feature request] Allow decentralizing the definition of the rules

See original GitHub issue

Hello,

Feature request

Is your feature request related to a problem? Please describe

I want to develop my server’s typeDefs/resolvers in a modular way. In order to do it, I need a way to collocate shield’s rules with my resolvers.

Describe the solution you’d like

I’d like to leverage the fact that we can declare a resolver using an object with the resolve key to add extra informations for my middlewares stack :

const resolvers = {
  Mutation: {
    createUser: {
      // pass rules using a special "permissions" key
      permissions: isAuthenticated,
      resolve: forwardTo('db')
    }
  }
}

Additional context

I already do this for my validation layer (big props to @JCMais for showing the way with his awesome post 👏 ) and it’s working great so far :

const resolvers = {
  Mutation: {
    createUser: {
      // pass rules using a special "permissions" key
      permissions: isAuthenticated,
      // pass validation rules to my yup-middleware
      validation: (_, __, { db }) =>
        update('data.username', f =>
          f.unique(async username => !(await db.exists.User({ username })))
        )
      resolve: forwardTo('db')
    }
  }
}

Implementation

@maticzav gave me hints about collecting all the rules from the schema using something like https://github.com/graphql-binding/graphql-binding/blob/master/src/fragmentReplacements.ts

Here you can still declare shield’s the current way by passing a map of your rules, but you can also overwrite them or define new ones using a special key inside your resolvers definitions (I pick ‘permissions’ by default, but it could be ‘shield’ as well, you can pick your own!)

const _ = require('lodash/fp')
const graphqlShield = require('graphql-shield')
const { middleware } = require('graphql-middleware')

function shield(initialPermissions = {}, options = {}) {
  const { permissionsKey = 'permissions', ...shieldOptions } = options
  return middleware(schema => {
    const permissions = _.merge(
      initialPermissions,
      collectPermissions(schema, permissionsKey)
    )
    return graphqlShield.shield(permissions, shieldOptions).generate(schema)
  })
}

function collectPermissions(schema, permissionsKey) {
  const resolvers = {
    Query: schema.getQueryType().getFields(),
    Mutation: schema.getMutationType().getFields()
  }
  let permissions = {}
  for (const typeName in resolvers) {
    const fieldResolvers = resolvers[typeName]
    for (const fieldName in fieldResolvers) {
      const fieldResolver = fieldResolvers[fieldName]
      if (fieldResolver[permissionsKey]) {
        permissions = _.set(
          [typeName, fieldName],
          fieldResolver[permissionsKey],
          permissions
        )
      }
    }
  }
  return permissions
}

module.exports = {
  ...graphqlShield,
  shield
}

Issue Analytics

  • State:closed
  • Created 5 years ago
  • Reactions:5
  • Comments:5 (1 by maintainers)

github_iconTop GitHub Comments

2reactions
JCMaiscommented, Sep 20, 2018

Btw, about this topic, I’ve created a RFC on graphql-js for having a supported way to declare this extra metadata directly on each field definition: https://github.com/graphql/graphql-js/issues/1527

Would love some opinions there

1reaction
jgouxcommented, Sep 20, 2018

how would you suggest the implementation of type- or schema-wide rules

I thought about type-wide rules and I didn’t find a proper solution for them yet. We can’t really declare them alongside the resolvers (at least using the regular syntax) because it’s not a valid GraphQL typedef. For now you can still declare them in the centralized config object.

For the schema-wide rules, let’s just keep them in the centralized configuration as they are global per se. 😄

I’ll publish the current implementation as a side-package then. Do you have any idea for the name? It will be the exact same API as shield, with the additional permissionsKey in the option object.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Decentralized Identifiers (DIDs) v1.0 - W3C
A globally unique persistent identifier that does not require a centralized registration authority and is often generated and/or registered cryptographically.
Read more >
What Is Decentralized Finance (DeFi) and How Does It Work?
Decentralized finance (DeFi) is an emerging financial technology based on secure distributed ledgers similar to those used by cryptocurrencies.
Read more >
What Is a Feature Request? Definition and Examples - Airfocus
A feature request is a comment, message, or ask from a user to implement a specific feature into your product. Feature requests can...
Read more >
DeFi risks and the decentralisation illusion
This special feature examines DeFi mainly from a financial stability perspective, drawing attention to vulnerabilities that stem from leverage ...
Read more >
What Are Decentralized Organizations? The Complete Guide
Organizations with a decentralized structure allow upper management ... This means business owners and top management can take a vacation, ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found