GraphQL Server permissions as another layer of abstraction.
Permission systems are the core of every application. Majority of servers thoroughly depend on data access manipulation, therefore, writing permissions should be simple yet powerful.
GraphQL Shield provides a straightforward approach to writing permissions in GraphQL servers. Its primary focus is abstracting permission layer efficiently from the logic layer of our server. Nevertheless, its raw power comes with dynamic caching which significantly reduces server load and accounts for faster query evaluation.
B.Q. — Before GraphQL ⏰
Handling requests one by one is simple. Each endpoint of REST API translates into precisely one response which requires, besides business logic of the application, only minute adjustments to data protection. Nevertheless, it has one significant flow — it is not efficient for the client. GraphQL tackles this magnificently. By giving the power of field selection to the client, we reduce the number of calls across the network and improve application speed.
REST servers required no dynamic caching. Server processed each request independently of the others; therefore our hands were, more or less, tight together. GraphQL, on the other hand, is obtaining data recursively. Our information is no longer obtained one by one but rather altogether. Because of this, we should reconsider switching our vintage, static permissions to active permissions layer which caches information intelligently.
GraphQL Shield for the win 🎉
GraphQL Shield manages permission layer intelligently and has an intuitive API. The process of implementing Shield into existing applications consists of two steps — defining rules and assigning them to schema, types or fields of the application. To better present the idea of this, we are going to build a small groceries shop application. In our application, we want to make sure people with no account see the products, the ones who are in the shop can see their prices and add them to their basket, and the owner of the shop should be able to add or remove existing products from the stock. Atop of this, we also want to make sure only admin can act as a store owner and only signed people can add items to their shopping carts. To follow this walkthrough more easily, I recommend you download the repository containing the end code, and follow the chunks of code that are described in more detail!
Apple, Banana, Orange — the model 🗺
We will start by creating a simple data model. Our application will consist of four types; these are the Grocer or the shop owner, the Customer, BasketItem and the Product. We are going to use Prisma to manage our data; therefore, we sum this up in the following file.
Resolvers — the juices ⚙️
Now that we have our data model constructed let’s think about functionality. As we said, we want to present available products to everyone. We want to allow our customers to see prices of their products and add them to their basket. Atop of that we also want to make sure that the grocer can add or remove new products from her inventory and manage the supply. I am not going to explain the mechanics behind each of the resolvers in detail as this is the topic for another blog post, but instead, present the schema itself which should give us enough information to tip to the next step. Here’s our application schema.
Orange can, but banana can’t — Permissions 🔒
Now, it is time we start thinking about permissions. We have three states — an unauthenticated user, an authenticated user who is also a customer, and an authenticated user who is a grocer. We can summarise these three states into a file below.
Simple, isn’t it? We define a rule block using a rule-function. A rule initialiser accepts two parameters but requires none of them. We could add additional options argument and tell shield whether we want to cache specific rule or not, or additional name property which would hard code the name of the function into the system. Shield caches all rules by default to improve the load time of the query. Because of this, there is no need for options argument if you are not planning to use Shield in advanced cases. Same goes for the name property. Shield by default makes sure no name is duplicated, and all names are assigned correctly. It is worth mentioning, though, that if you need such functionality, you can read more about it in the documentation.
The last step in the implementation of permission logic is defining which rules should cover which fields. Shield is exceptionally flexible when it comes to assigning your rule logic to the schema. In the groceries store example, we have defined all permissions in one file since our application is rather simple. To generate middleware from Shield we use shield function which reassures us that our rule model is flawless and generates middleware out of it.
Besides that, we could define permissions for each part of our application separately and merge them using ES6 rest spread syntax, or use not so old Object.assign method.
In this article, we have learned how to use Shield. We have created a simple Groceries shop application and applied permissions to our schema. This way, we were able to limit access to functionality in our application and gain control over our data.
This article is one of the examples of how to use Shield with your GraphQL Server. If you enjoyed reading it but didn’t understand all of it, be sure to drop a comment below or send me a direct message on Twitter where you can find me as @maticzav.
If you love GraphQL Shield project, support us by becoming a backer on OpenCollective! ❤️