#[macro_use] extern crate diesel; #[macro_use] extern crate diesel_migrations; use std::str::FromStr; use anyhow::Context; use actix_web::{web, App, HttpServer, HttpResponse, Responder, Result}; mod db; mod model; mod schema; use crate::db::DbPool; embed_migrations!("migrations"); #[derive(Debug, serde::Deserialize)] pub struct PersonCreateRequestData { name: String, age: i32, country: String, city: String, street: String, number: i32, } #[derive(Debug, serde::Serialize)] pub struct PersonCreateResponse { id: i32 } async fn create_person(db: web::Data, person: web::Json) -> impl Responder { log::debug!("Creating person = {:?}", person); let inner = |db: &DbPool, person: &PersonCreateRequestData| { let country = crate::model::Country::create_or_fetch(&db, &person.country)?; let city = crate::model::City::create_or_fetch(&db, &person.city)?; let street = crate::model::Street::create_or_fetch(&db, &person.street)?; let address = crate::model::Address::create_or_fetch(&db, &country, &city, &street, person.number)?; let person = crate::model::Person::create_or_fetch(&db, &address, &person.name, person.age)?; Ok(person.id()) }; inner(&db, &person) .map_err(|anyhow_error: anyhow::Error| { log::error!("{}", anyhow_error); HttpResponse::build(actix_web::http::StatusCode::INTERNAL_SERVER_ERROR).finish() }) .map(|id| HttpResponse::Ok().json(PersonCreateResponse { id })) } #[actix_web::main] async fn main() -> anyhow::Result<()> { env_logger::init_from_env(env_logger::Env::new().default_filter_or("info")); let bind = std::env::var("HOST").expect("environment: HOST variable not set"); let port = std::env::var("PORT") .as_ref() .map(|p| u16::from_str(p)) .expect("environment: PORT variable not set") .context("Failed to parse port as integer")?; let db_connection_pool = crate::db::establish_connection(); { let conn = db_connection_pool.get().expect("Failed to get connection from pool"); embedded_migrations::run_with_output(&conn, &mut std::io::stdout())?; } // drop `conn` here HttpServer::new(move || { App::new() .data(db_connection_pool.clone()) .route("/create", web::post().to(create_person)) }) .bind(format!("{}:{}", bind, port))? .run() .await .map_err(anyhow::Error::from) }