Rust Async-GraphQL Example: Caster API
DEPRECATION WARNING: This example is a few years old at this point, and will not be actively kept up-to-date. You may want to take a look at my new API framework, Nakago, which took the approach here and expanded on it with an async-first dependency injection system to make testing a lot easier. There's a version of this project there in the examples/async-graphql
folder.
This is an example app for the upcoming Rust video series by Brandon Konkle. It implements a basic API to support a number of hypothetical frontends for the imaginary "Caster" app, a tool to help podcasters, broadcasters, and streamers coordinate show content with their co-hosts and guests. Limited to just the API to support the front end.
Local Development
Install Rust with rustup.
Clippy
For helpful linting rools, install Clippy with rustup
:
rustup component add clippy
Run it with cargo
:
cargo clippy --fix
Configure the rust-analyzer
VS Code plugin to use it (in settings.json):
{
"rust-analyzer.checkOnSave.command": "clippy"
}
libclang
The cargo-spellcheck
utility depends on libclang
.
In Ubuntu, the package to install is libclang-dev
:
sudo apt install libclang-dev
Cargo Make
To build scripts from the Makefile.toml, install Cargo Make:
cargo install cargo-make
Run "setup" to install some tooling dependencies:
cargo make setup
Configuration
Configuration is unfortunately stored in two places, with the primary location being the config folder. This folder contains hierarchical config files that are read by Figment.
To set up your local environment, create a local.toml
file and a test.toml
file, using local.toml.example
and test.toml.example
as a guide.
The local.toml
config is loaded by default in every run mode. In addition, an attempt to load a config file with the name of the run mode is also made - for example, test.toml
when the run_mode
is "test".
This config is read in as part of a lazy_static
instance that is first initialized when the main.rs
module from the caster_api
app calls caster_utils::config::get_config()
.
Environment Variables
For CLI tools, we have to provide a small direnv .envrc
file with a subset of our config values so that tools like docker-compose
and sqlx-cli
can read them. Use the .envrc.example
as a guide.
Running Docker
To run the docker-compose formation with just the supporting services needed to run cargo make dev
:
cargo make docker up -d
To shut it down:
cargo make docker down
To run docker-compose with the API app included:
cargo make docker-api up -d
To shut it down:
cargo make docker-api down
SQLx CLI
Install the SQLx CLI for running migrations:
cargo install sqlx-cli --no-default-features --features rustls,postgres
Create a database based on the DATABASE_URL
in the .envrc
, if you haven't already:
cargo make db-create
Run migrations:
cargo make db-migrate
If you want to wipe your database and start over:
cargo make db-reset
Running the Local dev server
Use cargo
to run the dev server locally:
cargo make dev
Update Dependencies
First, install the outdated
command for cargo
:
cargo install --locked cargo-outdated
Then, update and check for any major dependency changes:
cargo update
cargo outdated
Running Integration Tests
To integration test, you need to have the Docker Compose stack with Postgres and Redis running locally, or within your CI pipeline.
NOTE: This is destructive, and will wipe out data within your local database. See below for how to use an alternate test database locally.
To run the integration tests:
cargo make integration
Using an Alternate Test Database
Running integration tests is destructive. If you want to preserve your local data, use an alternate database for local integration testing. Create a config/test.toml
file and customize the DATABASE_URL
:
[database]
name = "caster_rust_test"
url = "postgresql://caster:caster@localhost:1701/caster_rust_test"
Since the RUN_MODE
environment variable is set by the tasks.integration
make task to "test", this file will automatically be picked up by the config reader.
NOTE: To manage this test database with the SQLx CLI, you'll need to temporarily edit your .envrc
file to match the values above, and then run the command to reset the test database:
cargo make db-reset
You can restore the original values in your .envrc
afterwards.
Deployment
Building Docker Containers Locally
To build locally, use Buildkit:
DOCKER_BUILDKIT=1 docker build -t caster-api -f apps/api/Dockerfile .
To clear the build cache:
docker builder prune --filter type=exec.cachemount
To inspect the local filesystem:
docker run --rm -it --entrypoint=/bin/bash caster-api
To inspect the full build context:
docker image build --no-cache -t build-context -f - . <<EOF
FROM busybox
WORKDIR /build-context
COPY . .
CMD find .
EOF
docker container run --rm build-context
And to clean up the build context test image:
docker image rm build-context