How to select Rust crates
TLDR: This post contains some considerations for selecting rust crates and recommends to build toy examples to verify the selection. It also provides a toy CRUD example for the stack: axum-sqlx-sqlite-utoipa
Rust has a limited standard library
Rust is a very powerful, modern programming language.
However the challenge in using it for non-trivial things comes from the wide variety of 3-rd party dependencies (called crates) that you need.
The language itself contains a rather limited standard library.
For example when you want to create a web service you need additional crates.
Would the right crate for x please stand up
However there is a multitude of crates available (e.g. on crates.io ) and it is difficult to assess for each crate:
- is it still actively maintained or already considered deprecated by the Rust community
- is it safe code or does it use a lot of “unsafe” code (memory safety is a big advantage of Rust and crates which do not use idiomatic or safe approach might introduce problems)
- is it well maintained and does not introduce a lot of security issues
- does the crate not introduce a transitive list of other problematic dependencies which impacts compile and build times
For example for web backends we have
- Rocket - which is widely used but recently seems to be no longer well maintained
- actix-web - which seems to be the performance leader for production projects
- axum - the newcomer which uses safe code and may replace actix-web for hobbyist projects
- and countless others
Even if the selection of a single crate is sometimes quite easy, selecting a combination of crates that work together as a stack may be difficult
- one crate may be sync and the other async - so they are not compatible
- even if both crates are async they may use incompatible async runtimes (std versus tokio)
- even if they both use tokio async runtime they may have incompatible or redundant type systems (for error handling, or primitives like HTTP requests)
What we can do to address the problem - Example on building a Rest CRUD web service
To work around that challenge I find it best to implement small educational samples using the combination of crates that I plan to use for a project before I actually start on the real project.
This allows you to save time on your real project - you will not be forced later to refactor your real project to a new crate because you have already verified the functionality with a toy example.
Also creating a limited example is much faster and you already find examples in the web that help you to quickly stick the components together.
So by focusing on the technology selection rather than your own domain problem you come to a conclusion/selection more quickly.
Here is a combination of crates for building a CRUD Rest web service including persistence (database) that I found to be
- safe
- modern
- raising in adoption and community support
- all based on or compatible with tokio async runtime
Crate selection for toy project for CRUD Rest web service
- axum - for web
- sqlx with sqlite - for persistence
- utoipa - for OpenAPI/Swagger doc
You can find my example which uses this stack here
https://github.com/Bodobolero/axum_crud_api
The example includes error handling and e-2-e testcases.
Next steps
I plan to build the same sample app with actix-web and sqlx with postgres instead of sqlite.
To learn actix-web I decided to follow Luca Palmieri’s book Zero to production
I also want to extend it with a Rust WASM client implemented with yew
I can then make an informed decision whether to implement my real project with axum or actix-web and whether I will stick to sqlx or instead consider an ORM like diesel instead.