GraphQL is not a new concept and is definitely here to stay.
Since it was introduced in 2015 by Facebook, GraphQL has gained a lot of popularity and has influenced how developers and teams are structuring their APIs, moving away from REST API and generating queries, mutations and subscriptions.
There are a few key architectural changes which GraphQL has introduced. Some of them (as explained below) are for the best while some others are for the worst. This is extremely relevant in saas architecture where micro-services are in common use.
But how about security? Does GraphQL pose the same challenges as the traditional REST API? Is it easier? Or is it not?
This post will try to cover some of the differentiating factors between traditional REST API and GraphQL, from an architecture and security perspective.
GraphQL VS REST
Most of us know REST API when it comes to interactions between clients and servers. REST (which stands for Representational state transfer) is still the de-facto standard in how web services are being implemented these days.
With REST APIs we are using CRUD (Create, Read, Update, Delete) concepts over HTTP protocol (POST, GET, PUT, DELETE) to combine both into representation “language” based contracts.
OK… So it’s a standard… And everyone is using it… But is there still room to welcome the new kid on the block?
Obviously there is, as GraphQL has gained a lot of popularity over the last few years and used in enterprise applications development around the globe. But why? What is “wrong” with REST API that requires introducing yet another query language?
There are plenty of articles around the differences between REST API and GraphQL and we are not planning to list all them here. But it is worth mentioning the highlights of GraphQL and REST API.
Starting with the pros, GraphQL has some outstanding advantages over REST API:
- Non-fixed schema – With REST API, the server defines the schema and the client cannot “choose” which fields to get without additional coding on the backend. With GraphQL this is part of the query language and is supported by default
- Multiple sources – consuming data for multiple resources with REST API can cause multiple requests client – backend (for example getting list of users via GET /user and then getting assets per user at GET /user/:id/assets). This means doing N requests per number of users. With GraphQL we can easily define that we want to get for the users including their assets in one query.
But as always, cons are part of life too:
- Caching – One of the great capabilities of HTTP protocol is caching. That means that REST API leverages the caching mechanism. With GraphQL the used method is POST which means that NO request is being cached.
- Monitoring – With REST API, you can monitor specific endpoints and check for the number of requests and how long they take. With GraphQL (when everything points to /graphql this capability disappears making it really hard to monitor your API back end). This extremely useful with the rise of saas applications architecture concepts where each of the micro-services is separate is as a developer you want to be able to monitor each service separately
How about Security?
The standards around securing REST APIs are well known and when protecting specific routes and endpoints, we can make sure that they are accessible by specific authentications and authorizations.
For example using REST API, we can block ALL non authenticated calls on the NGINX (without sending them to the actual backend for further handling).
Alternatively we can block all /api calls and require authentication for them:
Or even that admin related APIs will require
admin role on the JWT:
So REST API is covered. But how do we do it using GraphQL? When all of the requests are going through https://api.acem.com/graphql, how do we protect our application from being hacked?
Dealing with the authentication first, we want to validate the JWT calls on each of our requests. This is done by using the context hook available on the GraphQL Apollo.
So now that we have the authentication part ready, how do we handle the authorization part? The context part is too “early” on in the chain to throw the error from.
Let’s take a look at the following example. Let’s say we have an assets query. We want to allow all authenticated users to get a list of assets but we only want administrators to actually add assets. Both users are authenticated but we need to make sure that only the permitted ones can add.
How do we leverage the use of context? Using the role on top of the context can help us to make sure that only authorized user can actually add assets.
We have the authentication and authorization part ready, but how about multi-tenancy? How do we make sure that we are loading the relevant assets for authenticated users only (and it’s relevant tenant)?
Again, the use of GraphQL context comes in handy. We need to use the context in order to filter the assets based on the relevant tenantID and when adding a new asset, making sure to store it within the relevant tenantId to avoid cross-tenant issues.
GraphQL is great.
In today’s world when building enterprise applications and saas applications, we want to cut development time and focus on api-first design. This is where GraphQL come in handy.
Developers love GraphQL as it makes things really easy for full stack teams to build and ship features much faster. However, it also poses some challenges when it comes to dealing with authentication and authorization especially when dealing with multi-tenant SaaS applications where each API returns data for multiple tenants from multiple roles.
The highlights mentioned above are only some of the items we need to pay attention to when dealing with multi-tenant authenticated applications.
Have any questions?
Feel free to drop us a line.