//! Run with //! //! ```not_rust //! cargo run -p example-diesel-postgres //! ``` //! //! Checkout the [diesel webpage](https://diesel.rs) for //! longer guides about diesel //! //! Checkout the [crates.io source code](https://github.com/rust-lang/crates.io/) //! for a real world application using axum and diesel use axum::{ extract::State, http::StatusCode, response::Json, routing::{get, post}, Router, }; use diesel::prelude::*; use diesel_migrations::{embed_migrations, EmbeddedMigrations, MigrationHarness}; use std::net::SocketAddr; use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt}; // this embeds the migrations into the application binary // the migration path is relative to the `CARGO_MANIFEST_DIR` pub const MIGRATIONS: EmbeddedMigrations = embed_migrations!("migrations/"); // normally part of your generated schema.rs file table! { users (id) { id -> Integer, name -> Text, hair_color -> Nullable, } } #[derive(serde::Serialize, Selectable, Queryable)] struct User { id: i32, name: String, hair_color: Option, } #[derive(serde::Deserialize, Insertable)] #[diesel(table_name = users)] struct NewUser { name: String, hair_color: Option, } #[tokio::main] async fn main() { tracing_subscriber::registry() .with( tracing_subscriber::EnvFilter::try_from_default_env() .unwrap_or_else(|_| format!("{}=debug", env!("CARGO_CRATE_NAME")).into()), ) .with(tracing_subscriber::fmt::layer()) .init(); let db_url = std::env::var("DATABASE_URL").unwrap(); // set up connection pool let manager = deadpool_diesel::postgres::Manager::new(db_url, deadpool_diesel::Runtime::Tokio1); let pool = deadpool_diesel::postgres::Pool::builder(manager) .build() .unwrap(); // run the migrations on server startup { let conn = pool.get().await.unwrap(); conn.interact(|conn| conn.run_pending_migrations(MIGRATIONS).map(|_| ())) .await .unwrap() .unwrap(); } // build our application with some routes let app = Router::new() .route("/user/list", get(list_users)) .route("/user/create", post(create_user)) .with_state(pool); // run it with hyper let addr = SocketAddr::from(([127, 0, 0, 1], 3000)); tracing::debug!("listening on {addr}"); let listener = tokio::net::TcpListener::bind(addr).await.unwrap(); axum::serve(listener, app).await.unwrap(); } async fn create_user( State(pool): State, Json(new_user): Json, ) -> Result, (StatusCode, String)> { let conn = pool.get().await.map_err(internal_error)?; let res = conn .interact(|conn| { diesel::insert_into(users::table) .values(new_user) .returning(User::as_returning()) .get_result(conn) }) .await .map_err(internal_error)? .map_err(internal_error)?; Ok(Json(res)) } async fn list_users( State(pool): State, ) -> Result>, (StatusCode, String)> { let conn = pool.get().await.map_err(internal_error)?; let res = conn .interact(|conn| users::table.select(User::as_select()).load(conn)) .await .map_err(internal_error)? .map_err(internal_error)?; Ok(Json(res)) } /// Utility function for mapping any error into a `500 Internal Server Error` /// response. fn internal_error(err: E) -> (StatusCode, String) where E: std::error::Error, { (StatusCode::INTERNAL_SERVER_ERROR, err.to_string()) }