Working with a Database
For our project we will use a PostgreSQL database.
You may be already thinking about how to provision that database both locally and in the cloud, and the amount of work that it will take to do so. But no worries, we will use Shuttle to do that for us.
Using Shuttle Shared Databases
Open this link to the Shuttle Docs and follow the instructions to create a shared database in AWS.
As you will be able to see, just by using a macro we will be able to get a database connection injected into our code and a database fully provisioned both locally and in the cloud.
So let's get started!
Adding the dependencies
Go to the Cargo.toml
file in the api > shuttle
folder and add the following dependencies to the ones you already have:
[dependencies]
...
# database
shuttle-shared-db = { version = "0.47.0", features = ["postgres", "sqlx"] }
sqlx = { version = "0.7", default-features = false, features = [
"tls-native-tls",
"macros",
"postgres",
"uuid",
"chrono",
"json",
] }
If you want to learn more about how to add dependencies to your Cargo.toml
file, please refer to the Cargo Docs.
We are adding the shuttle-shared-db dependency to get the database connection injected into our code and the SQLx dependency to be able to use the database connection.
Note that the SQLx dependency has a lot of features enabled. We will use them later on in the project.
If you want to learn more about features in Rust, please refer to the Cargo Docs.
Injecting the database connection
Now that we have the dependencies, we need to inject the database connection into our code.
Open the main.rs
file in the api > shuttle > src
folder and add the following code as the first parameter of the actix_web
function:
#![allow(unused)] fn main() { #[shuttle_shared_db::Postgres] pool: sqlx::PgPool, }
The function should look like this:
#![allow(unused)] fn main() { #[shuttle_runtime::main] async fn actix_web( #[shuttle_shared_db::Postgres] pool: sqlx::PgPool, ) -> ShuttleActixWeb<impl FnOnce(&mut ServiceConfig) + Send + Clone + 'static> { let config = move |cfg: &mut ServiceConfig| { cfg.service(hello_world); }; Ok(config.into()) } }
Let's build the project. We will get a warning because we're not using the pool
variable yet, but we will fix that in a moment.
cargo build
Running the project
Now that we have the database connection injected into our code, we can run the project and see what happens.
cargo shuttle run
You will see that the project is building and then it will fail with the following error:
Docker
The error is telling us that we need to have Docker running in our system.
Let's start Docker and run the project again.
cargo shuttle run
This time the project will build and run successfully.
Note that you will be able to find the connection string to the database in the logs. We will use that connection string later on in the project.
Commit your changes.
git add .
git commit -m "add database connection"