Skip to content

Commit cd0a19c

Browse files
authored
Add Axum+Diesel example (#629)
1 parent 3888a1b commit cd0a19c

File tree

5 files changed

+167
-0
lines changed

5 files changed

+167
-0
lines changed

examples/http-axum-diesel/Cargo.toml

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
[package]
2+
name = "http-axum-diesel"
3+
version = "0.1.0"
4+
edition = "2021"
5+
6+
7+
# Use cargo-edit(https://github.com/killercup/cargo-edit#installation)
8+
# to manage dependencies.
9+
# Running `cargo add DEPENDENCY_NAME` will
10+
# add the latest version of a dependency to the list,
11+
# and it will keep the alphabetic ordering for you.
12+
13+
[dependencies]
14+
axum = "0.6.4"
15+
bb8 = "0.8.0"
16+
diesel = "2.0.3"
17+
diesel-async = { version = "0.2.1", features = ["postgres", "bb8"] }
18+
lambda_http = { path = "../../lambda-http" }
19+
lambda_runtime = { path = "../../lambda-runtime" }
20+
serde = "1.0.159"
21+
tokio = { version = "1", features = ["macros"] }
22+
tracing = { version = "0.1", features = ["log"] }
23+
tracing-subscriber = { version = "0.3", default-features = false, features = ["ansi", "fmt"] }

examples/http-axum-diesel/README.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# AWS Lambda Function example
2+
3+
This example shows how to develop a REST API with Axum and Diesel that connects to a Postgres database.
4+
5+
## Build & Deploy
6+
7+
1. Install [cargo-lambda](https://github.com/cargo-lambda/cargo-lambda#installation)
8+
2. Build the function with `cargo lambda build --release`
9+
3. Deploy the function to AWS Lambda with `cargo lambda deploy --iam-role YOUR_ROLE`
10+
11+
## Build for ARM 64
12+
13+
Build the function with `cargo lambda build --release --arm64`
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
-- This file should undo anything in `up.sql`
2+
DROP TABLE posts
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
-- Your SQL goes here
2+
CREATE TABLE posts (
3+
id SERIAL PRIMARY KEY,
4+
title VARCHAR NOT NULL,
5+
content TEXT NOT NULL,
6+
published BOOLEAN NOT NULL DEFAULT FALSE
7+
)

examples/http-axum-diesel/src/main.rs

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
use axum::{
2+
extract::{Path, State},
3+
response::Json,
4+
routing::get,
5+
Router,
6+
};
7+
use bb8::Pool;
8+
use diesel::prelude::*;
9+
use diesel_async::{pooled_connection::AsyncDieselConnectionManager, AsyncPgConnection, RunQueryDsl};
10+
use lambda_http::{http::StatusCode, run, Error};
11+
use serde::{Deserialize, Serialize};
12+
13+
table! {
14+
posts (id) {
15+
id -> Integer,
16+
title -> Text,
17+
content -> Text,
18+
published -> Bool,
19+
}
20+
}
21+
22+
#[derive(Default, Queryable, Selectable, Serialize)]
23+
struct Post {
24+
id: i32,
25+
title: String,
26+
content: String,
27+
published: bool,
28+
}
29+
30+
#[derive(Deserialize, Insertable)]
31+
#[diesel(table_name = posts)]
32+
struct NewPost {
33+
title: String,
34+
content: String,
35+
published: bool,
36+
}
37+
38+
type AsyncPool = Pool<AsyncDieselConnectionManager<AsyncPgConnection>>;
39+
type ServerError = (StatusCode, String);
40+
41+
async fn create_post(State(pool): State<AsyncPool>, Json(post): Json<NewPost>) -> Result<Json<Post>, ServerError> {
42+
let mut conn = pool.get().await.map_err(internal_server_error)?;
43+
44+
let post = diesel::insert_into(posts::table)
45+
.values(post)
46+
.returning(Post::as_returning())
47+
.get_result(&mut conn)
48+
.await
49+
.map_err(internal_server_error)?;
50+
51+
Ok(Json(post))
52+
}
53+
54+
async fn list_posts(State(pool): State<AsyncPool>) -> Result<Json<Vec<Post>>, ServerError> {
55+
let mut conn = pool.get().await.map_err(internal_server_error)?;
56+
57+
let posts = posts::table
58+
.filter(posts::dsl::published.eq(true))
59+
.load(&mut conn)
60+
.await
61+
.map_err(internal_server_error)?;
62+
63+
Ok(Json(posts))
64+
}
65+
66+
async fn get_post(State(pool): State<AsyncPool>, Path(post_id): Path<i32>) -> Result<Json<Post>, ServerError> {
67+
let mut conn = pool.get().await.map_err(internal_server_error)?;
68+
69+
let post = posts::table
70+
.find(post_id)
71+
.first(&mut conn)
72+
.await
73+
.map_err(internal_server_error)?;
74+
75+
Ok(Json(post))
76+
}
77+
78+
async fn delete_post(State(pool): State<AsyncPool>, Path(post_id): Path<i32>) -> Result<(), ServerError> {
79+
let mut conn = pool.get().await.map_err(internal_server_error)?;
80+
81+
diesel::delete(posts::table.find(post_id))
82+
.execute(&mut conn)
83+
.await
84+
.map_err(internal_server_error)?;
85+
86+
Ok(())
87+
}
88+
89+
fn internal_server_error<E: std::error::Error>(err: E) -> ServerError {
90+
(StatusCode::INTERNAL_SERVER_ERROR, err.to_string())
91+
}
92+
93+
#[tokio::main]
94+
async fn main() -> Result<(), Error> {
95+
// required to enable CloudWatch error logging by the runtime
96+
tracing_subscriber::fmt()
97+
.with_max_level(tracing::Level::INFO)
98+
// disable printing the name of the module in every log line.
99+
.with_target(false)
100+
// this needs to be set to false, otherwise ANSI color codes will
101+
// show up in a confusing manner in CloudWatch logs.
102+
.with_ansi(false)
103+
// disabling time is handy because CloudWatch will add the ingestion time.
104+
.without_time()
105+
.init();
106+
107+
// Set up the database connection
108+
let db_url = std::env::var("DATABASE_URL").expect("missing DATABASE_URL environment variable");
109+
let config = AsyncDieselConnectionManager::<AsyncPgConnection>::new(db_url);
110+
let connection = Pool::builder()
111+
.build(config)
112+
.await
113+
.expect("unable to establish the database connection");
114+
115+
// Set up the API routes
116+
let posts_api = Router::new()
117+
.route("/", get(list_posts).post(create_post))
118+
.route("/:id", get(get_post).delete(delete_post));
119+
let app = Router::new().nest("/posts", posts_api).with_state(connection);
120+
121+
run(app).await
122+
}

0 commit comments

Comments
 (0)