Skip to content

Commit

Permalink
feat: add actix postgres example (#8)
Browse files Browse the repository at this point in the history
  • Loading branch information
oddgrd authored Dec 12, 2022
1 parent 8ada303 commit 7797994
Show file tree
Hide file tree
Showing 6 changed files with 96 additions and 5 deletions.
5 changes: 5 additions & 0 deletions actix-web/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Actix Web with shuttle

Normally one would configure an application with [Actix Web](https://docs.rs/actix-web/latest/actix_web/index.html) using the [App](https://docs.rs/actix-web/latest/actix_web/struct.App.html) struct. However, shuttle needs to move the users configuration across threads to start the server on our backend, and the `App` struct is `!Send` and `!Sync`.

That means that for shuttle to support Actix Web, we need to use the [ServiceConfig](https://docs.rs/actix-web/latest/actix_web/web/struct.ServiceConfig.html) struct. You should be able to configure your application like you normally would, but some steps may be a bit different. If you do you find something that you would expect to be possible not working, please reach out and let us know.
2 changes: 0 additions & 2 deletions actix-web/hello-world/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,5 @@ version = "0.1.0"
edition = "2021"

[dependencies]
actix-service = "2.0.2"
actix-web = "4.2.1"
shuttle-service = { version = '0.8.0', features = ["web-actix-web"] }

7 changes: 4 additions & 3 deletions actix-web/hello-world/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
use actix_web::web::{resource, ServiceConfig};
use actix_web::{get, web::ServiceConfig};
use shuttle_service::ShuttleActixWeb;

#[get("/hello")]
async fn hello_world() -> &'static str {
"Hello World!"
}

#[shuttle_service::main]
async fn actix_web(
) -> ShuttleActixWeb<impl FnOnce(&mut ServiceConfig) + Sync + Send + Copy + Clone + 'static> {
) -> ShuttleActixWeb<impl FnOnce(&mut ServiceConfig) + Sync + Send + Clone + 'static> {
Ok(move |cfg: &mut ServiceConfig| {
cfg.service(resource("/hello").to(hello_world));
cfg.service(hello_world);
})
}
13 changes: 13 additions & 0 deletions actix-web/postgres/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
[package]
name = "postgres"
version = "0.1.0"
edition = "2021"

[lib]

[dependencies]
actix-web = "4.2.1"
serde = "1.0.148"
shuttle-service = { version = "0.8.0", features = ["web-actix-web"] }
shuttle-shared-db = { version = "0.8.0", features = ["postgres"] }
sqlx = { version = "0.6.2", features = ["runtime-tokio-native-tls", "postgres"] }
6 changes: 6 additions & 0 deletions actix-web/postgres/schema.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
DROP TABLE IF EXISTS todos;

CREATE TABLE todos (
id serial PRIMARY KEY,
note TEXT NOT NULL
);
68 changes: 68 additions & 0 deletions actix-web/postgres/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
use actix_web::middleware::Logger;
use actix_web::{
error, get, post,
web::{self, Json, ServiceConfig},
Result,
};
use serde::{Deserialize, Serialize};
use shuttle_service::{error::CustomError, ShuttleActixWeb};
use sqlx::{Executor, FromRow, PgPool};

#[get("/{id}")]
async fn retrieve(path: web::Path<i32>, state: web::Data<AppState>) -> Result<Json<Todo>> {
let todo = sqlx::query_as("SELECT * FROM todos WHERE id = $1")
.bind(*path)
.fetch_one(&state.pool)
.await
.map_err(|e| error::ErrorBadRequest(e.to_string()))?;

Ok(Json(todo))
}

#[post("")]
async fn add(todo: web::Json<TodoNew>, state: web::Data<AppState>) -> Result<Json<Todo>> {
let todo = sqlx::query_as("INSERT INTO todos(note) VALUES ($1) RETURNING id, note")
.bind(&todo.note)
.fetch_one(&state.pool)
.await
.map_err(|e| error::ErrorBadRequest(e.to_string()))?;

Ok(Json(todo))
}

#[derive(Clone)]
struct AppState {
pool: PgPool,
}

#[shuttle_service::main]
async fn actix_web(
#[shuttle_shared_db::Postgres] pool: PgPool,
) -> ShuttleActixWeb<impl FnOnce(&mut ServiceConfig) + Sync + Send + Clone + 'static> {
pool.execute(include_str!("../schema.sql"))
.await
.map_err(CustomError::new)?;

let state = web::Data::new(AppState { pool });

Ok(move |cfg: &mut ServiceConfig| {
cfg.service(
web::scope("/todos")
.wrap(Logger::default())
.service(retrieve)
.service(add)
.app_data(state),
);
})
}

#[derive(Deserialize)]
struct TodoNew {
pub note: String,
}

#[derive(Serialize, Deserialize, FromRow)]
struct Todo {
pub id: i32,
pub note: String,
}

0 comments on commit 7797994

Please sign in to comment.