diff --git a/async_pg/.gitignore b/async_pg/.gitignore index 53eaa219..37c8717f 100644 --- a/async_pg/.gitignore +++ b/async_pg/.gitignore @@ -1,2 +1,3 @@ /target **/*.rs.bk +.env diff --git a/async_pg/Cargo.toml b/async_pg/Cargo.toml index c7d81273..20706a55 100644 --- a/async_pg/Cargo.toml +++ b/async_pg/Cargo.toml @@ -4,13 +4,14 @@ version = "0.1.0" authors = ["dowwie "] edition = "2018" - [dependencies] actix-rt = "1.0.0" actix-web = "2.0.0" -deadpool-postgres = "0.4.3" +config = "0.10.1" +deadpool-postgres = "0.5.0" derive_more = "0.99.2" -serde = { version = "1.0.104", features=["derive"] } +dotenv = "0.15.0" +serde = { version = "1.0.104", features = ["derive"] } tokio-pg-mapper = "0.1.4" tokio-pg-mapper-derive = "0.1.4" tokio-postgres = "0.5.1" diff --git a/async_pg/README.md b/async_pg/README.md index 4cedd651..5552fb6e 100644 --- a/async_pg/README.md +++ b/async_pg/README.md @@ -1,12 +1,72 @@ -This example illustrates: - - tokio_postgres - - use of tokio_pg_mapper for postgres data mapping - - deadpool_postgres for connection pooling +# async_pg example +## This example illustrates -# Instructions -1. Set up the testing database by running /sql/create_db.sh -2. `cargo run` -3. from the command line (linux), POST a user to the endpoint: - echo '{"email": "ferris@thecrab.com", "first_name": "ferris", "last_name": "crab", "username": "ferreal"}' | http -f --json --print h POST http://127.0.0.1:8080/users - - a unique constraint exists for username, so running this twice will return a 500 +- `tokio_postgres` +- use of `tokio_pg_mapper` for postgres data mapping +- `deadpool_postgres` for connection pooling +- `dotenv` + `config` for configuration + +## Instructions + +1. Create database user + + ```shell + createuser -P test_user + ``` + + Enter a password of your choice. The following instructions assume you + used `testing` as password. + + This step is **optional** and you can also use an existing database user + for that. Just make sure to replace `test_user` by the database user + of your choice in the following steps and change the `.env` file + containing the configuration accordingly. + +2. Create database + + ```shell + createdb -O test_user testing_db + ``` + +3. Initialize database + + ```shell + psql -f sql/schema.sql testing_db + ``` + + This step can be repeated and clears the database as it drops and + recreates the schema `testing` which is used within the database. + +4. Create `.env` file: + + ```ini + SERVER_ADDR=127.0.0.1:8080 + PG.USER=test_user + PG.PASSWD=testing + PG.HOST=127.0.0.1 + PG.PORT=5432 + PG.DBNAME=testing_db + PG.POOL.MAX_SIZE=16 + ``` + +5. Run the server: + + ```shell + cargo run + ``` + +6. Using a different terminal send an HTTP POST request to the running server: + + ```shell + echo '{"email": "ferris@thecrab.com", "first_name": "ferris", "last_name": "crab", "username": "ferreal"}' | http -f --json --print h POST http://127.0.0.1:8080/users + ``` + + **...or using curl...** + + ```shell + curl -d '{"email": "ferris@thecrab.com", "first_name": "ferris", "last_name": "crab", "username": "ferreal"}' -H 'Content-Type: application/json' http://127.0.0.1:8080/users + ``` + + A unique constraint exists for username, so sending this request twice + will return an internal server error (HTTP 500). diff --git a/async_pg/sql/create_db.sh b/async_pg/sql/create_db.sh deleted file mode 100755 index 6505d073..00000000 --- a/async_pg/sql/create_db.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -psql -U postgres -h 127.0.0.1 -f setup_db_and_user.sql diff --git a/async_pg/sql/setup_db_and_user.sql b/async_pg/sql/schema.sql similarity index 65% rename from async_pg/sql/setup_db_and_user.sql rename to async_pg/sql/schema.sql index dc515dd2..28efcc38 100644 --- a/async_pg/sql/setup_db_and_user.sql +++ b/async_pg/sql/schema.sql @@ -1,15 +1,6 @@ -DROP DATABASE IF EXISTS testing_db; - -CREATE USER test_user WITH PASSWORD 'testing'; - -CREATE DATABASE testing_db OWNER test_user; - -\connect testing_db; - DROP SCHEMA IF EXISTS testing CASCADE; CREATE SCHEMA testing; - CREATE TABLE testing.users ( id BIGSERIAL PRIMARY KEY, email VARCHAR(200) NOT NULL, diff --git a/async_pg/src/main.rs b/async_pg/src/main.rs index aa31f173..09bfb665 100644 --- a/async_pg/src/main.rs +++ b/async_pg/src/main.rs @@ -1,3 +1,20 @@ +mod config { + use serde::Deserialize; + pub use ::config::ConfigError; + #[derive(Deserialize)] + pub struct Config { + pub server_addr: String, + pub pg: deadpool_postgres::Config, + } + impl Config { + pub fn from_env() -> Result { + let mut cfg = ::config::Config::new(); + cfg.merge(::config::Environment::new())?; + cfg.try_into() + } + } +} + mod models { use serde::{Deserialize, Serialize}; use tokio_pg_mapper_derive::PostgresMapper; @@ -88,31 +105,25 @@ mod handlers { } use actix_web::{web, App, HttpServer}; -use deadpool_postgres::{Manager, Pool}; +use dotenv::dotenv; use handlers::add_user; -use tokio_postgres::{Config, NoTls}; +use tokio_postgres::NoTls; #[actix_rt::main] async fn main() -> std::io::Result<()> { - const SERVER_ADDR: &str = "127.0.0.1:8080"; + dotenv().ok(); - let pg_config = "postgres://test_user:testing@127.0.0.1:5432/testing_db" - .parse::() - .unwrap(); - - let pool = Pool::new( - Manager::new(pg_config, NoTls), - 16, // # of connections in pool - ); + let config = crate::config::Config::from_env().unwrap(); + let pool = config.pg.create_pool(NoTls).unwrap(); let server = HttpServer::new(move || { App::new() .data(pool.clone()) .service(web::resource("/users").route(web::post().to(add_user))) }) - .bind(SERVER_ADDR)? + .bind(config.server_addr.clone())? .run(); - println!("Server running at http://{}/", SERVER_ADDR); + println!("Server running at http://{}/", config.server_addr); server.await }