Headless CMS are all the rage from past some time. The idea of rendering a full page from the CMS itself for every request seems old & boring. To a certain point, the benefits of going Headless are valid & quantifiable.
To put it plainly, in a Headless implementation, the backend and frontend are separated out. The CMS (backend in this case) would just be responsible for managing the content. The frontend is decoupled from it & it can be built on an entirely different tech stack than what the backend is built on. Both frontend and backend are connected by an API (provided by backend) which the frontend uses to fetch data to display it on the screen. This way, the whole page (containing data + layout elements) would not have to be loaded and rendered for every request. This provides a few benefits right off the bat:
- Page loads become faster for the viewer
- Less data traffic between server and the client
- Server does not have to deal with layout construction for every request
But what does this have to do with GraphQL?
Well. there are currently two popular ways of getting the data from backend – REST API & GraphQL.
REST APIs have been around for a while. REST is an architectural concept for network based software. It doesn’t really have any set specifications and operates within a uniform set of protocols.
On the other hand, GraphQL is a query language designed to work off a single API endpoint which can handle different queries and return data specific to the query. Its a relatively new concept created by Facebook for their own use and it was released out in the open in 2015.
Making sense of it in WordPress world?
WordPress is mostly used to publish content, be it a small blog (like this one) or a large/very-popular publication like this or this, etc. Sure WordPress can be (and is being) used to run an online shop, or a discussion forum or a social network and it can also be used as a framework (see this & this) to build any other kind of app as well but its most common and popular use is for publishing content.
Off late I’ve been poking around GraphQL, trying to wrap my brains around it in context of using it with WordPress instead of using REST API and I’ve come across some interesting results.
Let’s see the numbers!
Set Up
At present there are two plugins available for WordPress for anyone wanting to use GraphQL:
WP-GraphQL is the most popular and stable of these two. So in my test, I decided to go with this one. I added a new post in WordPress with a bunch of text, an image and a shortcode. I created a simple frontend in Next.js which sends data request to WordPress on page load and displays it in un-styled HTML containers. Nothing fancy.
The Numbers
Each test was run with same parameters – 2 threads, 400 connections for a duration of 10 seconds.
And here are the results.
As its clearly visible, when using GraphQL, the server is able to handle 33.73 requests per second and sends approximately 10.8 KB of data per request. In case of REST API, the server is able to handle 48.05 requests per second and sends approximately 13.09 KB of data per request.
The REST API endpoint used here is the post
endpoint provided by WordPress out of the box.
But what happens if some sort of caching is added for the REST API?
As its evident in the above test, with some basic caching implemented, the server is able to handle 125.52 requests per second and sends approximately 13.05 KB of data per request. The data sent per request is similar to uncached test because the data being sent is same in both cases – the only difference is that the server is able to handle more requests now than it was able to handle earlier.
One of the common arguments heard in favour of GraphQL is that it sends only the data that is queried whereas with REST API a lot of unnecessary data is sent by the server which increases the payload size. So it was only right to create a custom REST API endpoint in my WordPress install which would send only the data that is needed on the frontend.
So now, with the custom REST API endpoint sending only the specific data needed on frontend and thus lack of any additional queries being run, the server is able to handle 53.24 requests per second and sends approximately 11.25 KB of data per request.
Since these are small numbers with seemingly negligible differences, let’s see them in perspective of percentages. With the custom REST API endpoint, what we see is an increase of 10.8% in server’s ability to handle requests and a reduction of 14.06% in the data being sent by the server.
And just like earlier, with some basic caching implemented, the server is able to handle 130.76 requests per second and sends approximately 11.28 KB of data per request.
What gives?
This is some basic rudimentary testing akin to the “Hello World” tests run with different frameworks/stacks to see which one is faster. While in those tests the spin-up time of a framework/stack can be a polarizing factor (because most tests do not account for it, don’t do multiple runs and average out their numbers), it would not be the case here because WordPress is spinning up in both cases – be it GraphQL or REST API.
I’ve not looked deeply into the WP-GraphQL plugin code or in the webonyx/graphql-php package it uses for the GraphQL parsing, so I cannot comment about the architecture and how things have been implemented for use with WordPress. I do dislike the abundant use of closures in both WP-GraphQL plugin and the graphql-php package; this is a mindset that carries over from the Javascript world and a lot of Javascript developers who write PHP code tend to gravitate towards use of closures compared to those who are predominantly PHP developers or those who come from Java/C# or Go or C++ etc background.
One thing that I can say is that using WP-GraphQL, on a level where scalability matters, could be problematic and raise performance concerns. For most sites, it wouldn’t be much of an issue but when you are playing on a level where you get hit by a few million viewers per day/week, then you tend to be more careful about your website’s performance.
And it might just not be WP-GraphQL plugin. GraphQL itself has a bunch of issues with performance in such a scenario where the data does not change per request. One of the biggest disadvantages of GraphQL is that the application on the backend is hit for every request – you just cannot leverage network caching solutions. While on the other hand, REST API requests in this case rely on URLs and each type of request has a unique & fixed URL – whose output can be cached, thus eliminating the need to hit WordPress for every request. This not only speeds things up for the viewers but also improves the performance of the website as the server is able to handle way more requests per second.
Caching with GraphQL is problematic – it has to be done at application level using something like Memcached or Redis etc.
Read more on differences in caching between REST & GraphQL here.
And I’m not going to touch on the topics of additional complexities of queries, the overhead of query parsing and non-versioned structure of data retrieval in GraphQL. Those are lengthy topics on their own and very subjective.
Closing remarks!
GraphQL is not a magic bullet. And it will not give best results for every situation.
Most developers I’ve seen tend to gravitate towards the new & shiny, the cool stuff. GraphQL is (still) shiny & cool – it can be a fantastic tool for the right job. But (from what I have seen & read & learnt about it so far) in my opinion it might not be suitable for use with WordPress on a content publication website where scale matters, at least at present.
It is an evolving stack and maybe down the line it could improve to the point where it becomes more viable. But for now, it is good in some situations and it does not work well in other situations.