Skip to content

A Rust implementation of the Realworld demo app spec using Axum and SQLx.

License

Notifications You must be signed in to change notification settings

brannan/realworld-axum-sqlx

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

54 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

realworld-axum-sqlx

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!

This is a fork of a fork! PSB

I fixed some compilation errors stemming from library updates. Note that I couldn't make it work with sqlx 7. HTTP port was made configurable.

A models module was created and database logic moved there.

Logic was moved from mod.rs files into named files. I hate having an editor with multiple mod.rs tabs open.

My goal is to have models separate from routing and to be able to mock the model controllers for unit testing.

In light of that I have implemented a master Store trait in src/models/mod.rs and dyn model controller traits for src/models/user.rs and src/models/profile.rs.

Both src/http/users.rs and src/http/profiles.rs now have unit tests. My solution seems convoluted and my limited rust experience may be preventing me from seeing the simple solution.

I am open to suggestions.

The architecture does, nevertheless, work just fine.

This is a fork!

Note that this repo is a fork of https://github.com/launchbadge/realworld-axum-sqlx that has been updated to the latest version of axum and sqlx.

Note: "I" vs "we"

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.

Project Structure

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.

Code Tour

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.

Setup

Clone this Repository

$ git clone https://github.com/launchbadge/realworld-axum-sqlx
$ cd realworld-axum-sqlx

Installing Rust and Cargo

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.

Installing sqlx-cli

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

Running 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 Application

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.

Setting Up the Application Database

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

Starting the Application

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.

License

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.

Contributing

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.

About

A Rust implementation of the Realworld demo app spec using Axum and SQLx.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • Rust 97.6%
  • PLpgSQL 2.4%