A Rust implementation of the Realworld demo app spec showcasing the use of the Axum web framework and SQLx SQL database client, with PostgreSQL as the database backend.
This project also serves as a commentary on the Realworld spec and how realistic it actually is, as well as what a particular senior developer at Launchbadge currently considers to be best practices. Best practices are always in flux, and a major point of this project was to experiment with project architecture and suss out what those best practices might look like.
Feedback is appreciated!
All comments in this project were (currently) written by a single person, and represent primarily that person's opinions and observations. When a comment uses "we", it does not necessarily indicate an authoritative position taken by Launchbadge, but rather an interpretation, by that one person, of the current consensus at Launchbadge, or an observation of a particular sentiment shared by several developers at Launchbadge.
This project uses the 2015/1.0.0 module structure, with mod.rs
files for modules with children,
as opposed to the 2018 (or "new") module style introduced in RFC 2126, where mod.rs
files are optional
and adding children to a module foo.rs
is as simple as creating a foo/
directory.
This is a style choice we vacillated on for a while at Launchbadge. However, we ultimately decided that the 2018 module style results in a lot of papercuts during rapid development, which is antithetical to its original design.
Namely, because most file management GUIs sort files separately from folders, you have to jump between two completely different places in the visualized file tree when transitioning between a parent module and its children. This is highly confusing to developers who were already used to the original module system when the 2018 style was introduced.
On its own, this would have been manageable, but it is made worse by the fact that the new style isn't
recommended by default in the 2018 edition and there is no lint in rustc
to enforce consistency*, so it becomes really
easy to mix and match styles accidentally when multiple developers with varying experience levels are contributing to a
project, or jumping back and forth between projects.
In retrospect, the 2018 edition should have involved a wholesale transition, banning mod.rs
files by default and
providing a migration path with cargo fix
, like with the other changes proposed in RFC 2126.
I understand why the language team was hesitant to do this, as it had the weakest set of justifications of all
the changes proposed in the RFC, but their indecision resulted in, IMHO, a far, far worse situation.
* Lints for this were only recently added to Clippy,
several years after the 2018 style was introduced. As of writing, the rust-lang/rust
repo itself mixes both
styles in various directories, which is frankly quite horrifying.
If you're familiar with SQL, I recommend starting in the migrations/
directory, as that's what contains the SQL files
that define the schema of the PostgreSQL database, which is usually the first thing done when prototyping a new project.
The files there are filled with comments explaining the various decisions made while structuring the database,
as well as advice on good practices for schema architecture and how this compares to the Realworld spec.
Next, of course, is main.rs
as the entrypoint for the application. It shows the typical boilerplate that goes
into spinning up a Rust backend application.
I then recommend going to lib.rs
and recursively exploring the modules as they're defined.
Comments on the module definitions will guide you from there.
$ git clone https://github.com/launchbadge/realworld-axum-sqlx
$ cd realworld-axum-sqlx
Install Rust as described in The Rust Programming Language, chapter 1.
This is the official Rust language manual and is freely available on doc.rust-lang.org.
The latest stable version is fine.
SQLx provides a command-line tool for creating and managing databases as well as migrations. It is published
on the Cargo crates registry as sqlx-cli
and can be installed like so:
$ cargo install sqlx-cli --features postgres
By far the easiest way to run Postgres these days is using a container with a pre-built image.
The following command will start version 14 of Postgres (the latest at time of writing) using Docker (this command should also work with Podman, a daemonless FOSS alternative).
$ docker run -d --name postgres-14 -p 5432:5432 -e POSTGRES_PASSWORD={password} postgres:14
Set {password}
to a password of your choosing.
Ensure the Postgres server is running:
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
621eb8962016 postgres:14 "docker-entrypoint.s…" 30 seconds ago Up 30 seconds 0.0.0.0:5432->5432/tcp, :::5432->5432/tcp postgres-14
Configuring the backend application is done, preferentially, via environment variables. This is the easiest way to pass sensitive configuration data like database credentials and HMAC keys in a deployment environment such as Kubernetes secrets.
To make working with environment variables easier during development, we can use .env files to avoid having to define the variables every time.
As a starting point, you can simply cp .env.sample .env
in this repo and modify the .env
file as described by
the comments there.
With sqlx-cli
installed and your .env
file set up, you only need to run the following command to get the
Postgres database ready for use:
$ sqlx db setup
With everything else set up, all you should have to do at this point is:
$ cargo run
If successful, the Realworld-compatible API is now listening at port 8080.
All code in this project is licensed under the GNU Affero General Public License (AGPL).
The AGPL is an extension of the GPL which includes interacting with the application over a computer network in its definition of "distribution" for applying the license terms. If you modify this project and host it in a location that is accessible to the web, you must make the source available as per the terms of the license.
See LICENSE in this repository for the text of the AGPL.
Because enforcement of the AGPL requires that we own the copyright on the whole project, any contributions to this project must be explicitly assigned copyright to Launchbadge, LLC. We're still researching the best route to do this, so while we will allow PRs to be opened against this repository, they may not be merged right away.