Taking a break from OpenAPI for a bit, I decided to explore the primary alternative for web API development—GraphQL. I've been pleasantly surprised so far at how easy it's been to write a GraphQL API using Rust, much easier than doing so with the OpenAPI tools I've tested so far.
There are two real contenders for GraphQL crates: async-graphql and Juniper. Having read briefly through both sets of documentation, async-graphql seemed like the more feature-rich and well-documented option, so that's what I went with. If you'd like me to take a look at Juniper and do an in-depth comparison, please leave a note in the discussion thread!
The good news is that both solutions are fairly feature-complete using stable Rust, and neither is tightly coupled to a web server! You'll know that this is perfect for my use-cases if you've read my previous posts where I repeatedly jumped through hoops shoe-horning a web server into a serverless environment.
As I mentioned, I went with async-graphql as the primary crate to build my experiment with. I used a similar AWS CDK setup as in my previous post since it was the easiest and most robust way to both test Rust lambdas locally and to deploy them to AWS.
Interested in seeing how to apply this CDK setup to Python applications? Upvote this idea thread.
I used cargo-make to orchestrate a bunch of tasks (I highly recommend you check it out if you find yourself using
Makefiles with Rust). Postgres via
docker-compose is my go-to database, though you can easily swap in MySQL or MSSQL since I'm using SQLx to run queries. Throw in a bit of tracing following the examples of the fantastic Zero to Production in Rust book, and we've got ourselves a pretty solid development platform for building our API.
You can explore the codebase yourself by looking at this repo, but here's quick rundown. The code consists of two main pieces: the handler and the API.
The handler is the same sort of thing I've written for previous posts—it's the bridge between the
lamedh_ crates (for interfacing with AWS Lambda) and async-graphql. All of that is in its own
handler.rs file, so it could be easily split out into a crate in the future. It's a bit messy with all the generic-handling, but if you were to couple it to your specific schema then the code would look a lot cleaner.
Would you be interested in a lamedh + async-graphql crate so you don't have to write your own handler? Let me know in the discussion thread.
The API code is fairly simple, for the most part you can just follow the docs. There are a few things that I struggled to find the answers to—and a few things I haven't yet solved—but generally you just start writing structs and resolver functions, and your GraphQL API comes to life.
I'm considering putting together a full tutorial on how to build a GraphQL API with Rust and host it with serverless technologies. It would cover auth, subscriptions via websockets, authenticating the GraphiQL UI, the works. If that's something you want, drop a note in the discussion thread and tell me how much, if anything, you'd be willing to pay for such a resource.
Building a GraphQL API in Rust using AWS Lambda to host it is way easier than trying to build the equivalent with OpenAPI. The main problem is the lack of an end-to-end guide covering everything you need to know. The
async-graphql docs are great, but terse (as are the
SQLx docs), so more are needed to make this setup more accessible. There are of course some major differences between GraphQL and OpenAPI (upvote this idea if you want a full comparison), so you'd have to be sold on GraphQL already to use this solution. All of that said, this is definitely my favorite solution for making APIs with Rust that I've tried so far.
Was this post super helpful to you? Tip me on GitHub.
Have a question or comment about this post? Leave it in the discussion thread on GitHub!
Have an idea or request for a future blog topic? Drop it in the GitHub discussions under ideas.