//! Run with //! //! ```sh //! export DATABASE_URL=postgres://localhost/your_db //! diesel migration run //! cargo run -p example-diesel-async-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::{ async_trait, extract::{FromRef, FromRequestParts, State}, http::{request::Parts, StatusCode}, response::Json, routing::{get, post}, Router, }; use diesel::prelude::*; use diesel_async::{ pooled_connection::AsyncDieselConnectionManager, AsyncPgConnection, RunQueryDsl, }; use std::net::SocketAddr; use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt}; // 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, } type Pool = bb8::Pool>; #[tokio::main] async fn main() { tracing_subscriber::registry() .with( tracing_subscriber::EnvFilter::try_from_default_env() .unwrap_or_else(|_| "example_diesel_async_postgres=debug".into()), ) .with(tracing_subscriber::fmt::layer()) .init(); let db_url = std::env::var("DATABASE_URL").unwrap(); // set up connection pool let config = AsyncDieselConnectionManager::::new(db_url); let pool = bb8::Pool::builder().build(config).await.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 mut conn = pool.get().await.map_err(internal_error)?; let res = diesel::insert_into(users::table) .values(new_user) .returning(User::as_returning()) .get_result(&mut conn) .await .map_err(internal_error)?; Ok(Json(res)) } // we can also write a custom extractor that grabs a connection from the pool // which setup is appropriate depends on your application struct DatabaseConnection( bb8::PooledConnection<'static, AsyncDieselConnectionManager>, ); #[async_trait] impl FromRequestParts for DatabaseConnection where S: Send + Sync, Pool: FromRef, { type Rejection = (StatusCode, String); async fn from_request_parts(_parts: &mut Parts, state: &S) -> Result { let pool = Pool::from_ref(state); let conn = pool.get_owned().await.map_err(internal_error)?; Ok(Self(conn)) } } async fn list_users( DatabaseConnection(mut conn): DatabaseConnection, ) -> Result>, (StatusCode, String)> { let res = users::table .select(User::as_select()) .load(&mut conn) .await .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()) }