Graphene vs Strawberry:
Which is better for providing a GraphQL API?
In M&P we have few projects using GraphQL APIs. And since most of the backends are created with Python and Django, we used the most starred GraphQL library for Python, which is Graphene. It has a good enough integration with Django, and we were pleased with the setup, until recently, we found that a lot of libraries around it are not maintained that well anymore, and it blocked us from updates.
Also, we had few issues with DX, so we started looking for an alternative, then we identified cases where DX with Graphene was not that great and checked how does it work with Strawberry.
1. Authentication
Graphene
There is no built-in mutations for user registration and authentication in Graphene. So, when we were looking for an existing solution, we stumbled across this library.
It provides quite a lot: JWT-based authentication, mutations to register a user, obtain JWT token, refresh token, recover password, activate account. All with email templates. It is well documented as well, so we used it in our projects. Unfortunately, it is not maintained anymore and blocks updates of other dependencies.
Strawberry
So, we checked whether there are existing solutions for Strawberry.
There is no library which provides all the same functionality as django-graphql-auth
, but there is a much simpler solution in the Django integration library.
It provides mutations for the user registration, login, and logout. The mutations themselves are not really flexible, but quite small and easy to inherit/extend or rewrite if needed.
The approach to authentication is much simpler than with Graphene’s graphql-auth
library. It reuses default Django authentication, and it’s much easier to integrate and work with. Also, web sockets and file downloads get authentication out of the box. So in most of our cases it works better than JWT-based authentication.
See https://strawberry-graphql.github.io/strawberry-graphql-django/references/authentication/ for more information.
Current Standing:
Strawberry: ⭐️
Graphene:
2. CUD operations on Django models
Graphene
There are few ways to do CUD (create, update, delete) operations on Django models in Graphene without much boilerplate:
Built in into Django integration:
DjangoModelFormMutation — which does not work if you have relay (and you are forced to have it if you use Graphene Django filters integration)
Django REST Framework SerializerMutation — the same problem as above, plus you need to add Django rest framework as a dependency even if you only need this kind of mutation.
Third party:
There is graphene-django-plus library, which does this job well, but unfortunately, it is not maintained anymore.
Strawberry
CUD operations on Django models provided by the same library which provides authentication.
There are few drawbacks, though:
The crud model provided by the library is not very flexible. For example, the name of the input variable cannot be changed.
Update mutation is implemented in a way that it allows you to update multiple rows at once. That is not needed in most of our cases and also make it quite easy to create update mutation which can update more than was intended.
We tried to find whether it can be overridden and found out that it is actually effortless to copy or extend necessary mutations.
The CUD mutations implementation can be found here https://github.com/strawberry-graphql/strawberry-graphql-django/blob/main/strawberry_django/mutations/fields.py
And we managed to create our own update mutation which accepts a mandatory ID attribute and data to perform update on a single row.
Current Standing:
Strawberry: ⭐️⭐️
Graphene:️
3. Subscriptions
On the frontend, there are two implementations of GraphQL over WebSocket subscriptions-transport-ws (outdated) and graphql-ws (new and shiny one).
We have projects with Graphene having subscriptions. Because of the unmaintained dependencies, we had problems setting it up compatible with graphql-ws
.
Strawberry subscriptions worked out of the box with the new protocol.
In both cases, using a subscription over Web Sockets together with queries and mutations over HTTP may require you to implement custom contexts or handle authentication slightly different.
Current Standing:
Strawberry: ⭐️⭐️⭐️
Graphene:️
4. Data loaders
Before v3, Graphene used promise-based Data loaders. After v3 was introduced, the documentation was broken for a long time, and it was not clear how to make them work. These days it seems it is fixed, and you can just use aiodataloader
package.
In Strawberry, they have got their own async data loaders, which just work.
Current Standing:
This is a draw, so no changes in the standing here
5. Cyclic imports handling
With GraphQL it is really easy to introduce cyclic dependencies. For example, in a blog application you may have User -> Blog -> Comment -> User
chain.
Both libraries provide solutions to work with such dependencies.
In Graphene, you may use strings or lambdas. For example:
But in case with lambda you may still have circular imports problem.
Strawberry make usetyping.Annotated
and strawberry.lazy
to solve the circular dependencies problem.
Lazy Types | 🍓 Strawberry GraphQL
Since with this approach imports can be guarded with if TYPE_CHECKING
this also solves circular imports problem.
The only problem I found is that if you import from __future__ import annotations
it breaks these lazy types and the error message is very cryptic and impossible to understand.
Current Standing:
Strawberry: ⭐️⭐️⭐
Graphene: ️️
6. Unit testing
Both libraries provide equal functionality, which allows you to execute any query on a schema.
We were particularly interested whether Strawberry can provide anything to serialize a specific type, but there was nothing built-in, but there are ways to execute requests with mock context, root values. So, we end up with the following helper:
That can allow testing serialization of mock models not yet stored to the database:
It should be possible to do the same with Graphene.
Current Standing:
This is a draw, so no changes in the standing here
7. GitHub insights
Just looking at GitHub insights, strawberry seems better maintained
Press enter or click to view image in full size
Current Standing:
Strawberry: ⭐️️️⭐️⭐️⭐⭐️️️
Graphene: ️
Conclusion: Strawberry is the Winner! 🍓
Both libraries provide more or less the same, but developer experience was much better with Strawberry. Most of the things just worked as expected and there were no problems with dependencies and libraries incompatibilities.
The integration with Django is not perfect, but where it is needed it is possible to reuse something and add overrides.