chore: Upgrade to Actix Web 4 (#638)

* chore: Upgrade to actix-web 4

* fix: Update example names for CI tests
This commit is contained in:
Cobalt 2022-04-02 16:00:49 +02:00 committed by GitHub
parent d547e107bc
commit 6a22207944
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
29 changed files with 87 additions and 80 deletions

View File

@ -293,7 +293,7 @@ jobs:
fail-fast: false fail-fast: false
matrix: matrix:
os: [ubuntu-latest] os: [ubuntu-latest]
path: [basic, actix_example, actix4_example, axum_example, axum-graphql_example, rocket_example, poem_example, jsonrpsee_example] path: [basic, actix_example, actix3_example, axum_example, axum-graphql_example, rocket_example, poem_example, jsonrpsee_example]
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2

View File

@ -0,0 +1,3 @@
HOST=127.0.0.1
PORT=8000
DATABASE_URL="mysql://root:root@localhost/actix_example"

View File

@ -1,5 +1,5 @@
[package] [package]
name = "sea-orm-actix-4-beta-example" name = "sea-orm-actix-example"
version = "0.1.0" version = "0.1.0"
authors = ["Sam Samai <sam@studio2pi.com.au>"] authors = ["Sam Samai <sam@studio2pi.com.au>"]
edition = "2021" edition = "2021"
@ -9,12 +9,12 @@ publish = false
members = [".", "entity", "migration"] members = [".", "entity", "migration"]
[dependencies] [dependencies]
actix-files = "0.6.0-beta.4" actix-http = "2"
actix-http = "=3.0.0-beta.5" actix-web = "3"
actix-rt = "2.2.0" actix-flash = "0.2"
actix-service = "=2.0.0-beta.5" actix-files = "0.5"
actix-web = "=4.0.0-beta.5" futures = { version = "^0.3" }
futures-util = { version = "^0.3" }
tera = "1.8.0" tera = "1.8.0"
dotenv = "0.15" dotenv = "0.15"
listenfd = "0.3.3" listenfd = "0.3.3"

View File

@ -1,6 +1,8 @@
![screenshot](Screenshot.png) ![screenshot](Screenshot.png)
# Actix 4 Beta with SeaORM example app # Actix 3 with SeaORM example app
> Actix Web 3 has been superseeded by [Actix Web 4](https://github.com/actix/actix-web).
1. Modify the `DATABASE_URL` var in `.env` to point to your chosen database 1. Modify the `DATABASE_URL` var in `.env` to point to your chosen database

View File

Before

Width:  |  Height:  |  Size: 604 KiB

After

Width:  |  Height:  |  Size: 604 KiB

View File

@ -17,7 +17,7 @@ version = "^0.7.0"
features = [ features = [
"macros", "macros",
"debug-print", "debug-print",
"runtime-actix-native-tls", "runtime-async-std-native-tls",
"sqlx-mysql", "sqlx-mysql",
# "sqlx-postgres", # "sqlx-postgres",
# "sqlx-sqlite", # "sqlx-sqlite",

View File

@ -1,4 +1,4 @@
use actix_files::Files as Fs; use actix_files as fs;
use actix_web::{ use actix_web::{
error, get, middleware, post, web, App, Error, HttpRequest, HttpResponse, HttpServer, Result, error, get, middleware, post, web, App, Error, HttpRequest, HttpResponse, HttpServer, Result,
}; };
@ -34,7 +34,11 @@ struct FlashData {
} }
#[get("/")] #[get("/")]
async fn list(req: HttpRequest, data: web::Data<AppState>) -> Result<HttpResponse, Error> { async fn list(
req: HttpRequest,
data: web::Data<AppState>,
opt_flash: Option<actix_flash::Message<FlashData>>,
) -> Result<HttpResponse, Error> {
let template = &data.templates; let template = &data.templates;
let conn = &data.conn; let conn = &data.conn;
@ -58,6 +62,11 @@ async fn list(req: HttpRequest, data: web::Data<AppState>) -> Result<HttpRespons
ctx.insert("posts_per_page", &posts_per_page); ctx.insert("posts_per_page", &posts_per_page);
ctx.insert("num_pages", &num_pages); ctx.insert("num_pages", &num_pages);
if let Some(flash) = opt_flash {
let flash_inner = flash.into_inner();
ctx.insert("flash", &flash_inner);
}
let body = template let body = template
.render("index.html.tera", &ctx) .render("index.html.tera", &ctx)
.map_err(|_| error::ErrorInternalServerError("Template error"))?; .map_err(|_| error::ErrorInternalServerError("Template error"))?;
@ -78,7 +87,7 @@ async fn new(data: web::Data<AppState>) -> Result<HttpResponse, Error> {
async fn create( async fn create(
data: web::Data<AppState>, data: web::Data<AppState>,
post_form: web::Form<post::Model>, post_form: web::Form<post::Model>,
) -> Result<HttpResponse, Error> { ) -> actix_flash::Response<HttpResponse, FlashData> {
let conn = &data.conn; let conn = &data.conn;
let form = post_form.into_inner(); let form = post_form.into_inner();
@ -92,9 +101,12 @@ async fn create(
.await .await
.expect("could not insert post"); .expect("could not insert post");
Ok(HttpResponse::Found() let flash = FlashData {
.append_header(("location", "/")) kind: "success".to_owned(),
.finish()) message: "Post successfully added.".to_owned(),
};
actix_flash::Response::with_redirect(flash, "/")
} }
#[get("/{id}")] #[get("/{id}")]
@ -122,7 +134,7 @@ async fn update(
data: web::Data<AppState>, data: web::Data<AppState>,
id: web::Path<i32>, id: web::Path<i32>,
post_form: web::Form<post::Model>, post_form: web::Form<post::Model>,
) -> Result<HttpResponse, Error> { ) -> actix_flash::Response<HttpResponse, FlashData> {
let conn = &data.conn; let conn = &data.conn;
let form = post_form.into_inner(); let form = post_form.into_inner();
@ -135,13 +147,19 @@ async fn update(
.await .await
.expect("could not edit post"); .expect("could not edit post");
Ok(HttpResponse::Found() let flash = FlashData {
.append_header(("location", "/")) kind: "success".to_owned(),
.finish()) message: "Post successfully updated.".to_owned(),
};
actix_flash::Response::with_redirect(flash, "/")
} }
#[post("/delete/{id}")] #[post("/delete/{id}")]
async fn delete(data: web::Data<AppState>, id: web::Path<i32>) -> Result<HttpResponse, Error> { async fn delete(
data: web::Data<AppState>,
id: web::Path<i32>,
) -> actix_flash::Response<HttpResponse, FlashData> {
let conn = &data.conn; let conn = &data.conn;
let post: post::ActiveModel = Post::find_by_id(id.into_inner()) let post: post::ActiveModel = Post::find_by_id(id.into_inner())
@ -153,9 +171,12 @@ async fn delete(data: web::Data<AppState>, id: web::Path<i32>) -> Result<HttpRes
post.delete(conn).await.unwrap(); post.delete(conn).await.unwrap();
Ok(HttpResponse::Found() let flash = FlashData {
.append_header(("location", "/")) kind: "success".to_owned(),
.finish()) message: "Post successfully deleted.".to_owned(),
};
actix_flash::Response::with_redirect(flash, "/")
} }
#[actix_web::main] #[actix_web::main]
@ -179,10 +200,11 @@ async fn main() -> std::io::Result<()> {
let mut listenfd = ListenFd::from_env(); let mut listenfd = ListenFd::from_env();
let mut server = HttpServer::new(move || { let mut server = HttpServer::new(move || {
App::new() App::new()
.service(Fs::new("/static", "./static"))
.data(state.clone()) .data(state.clone())
.wrap(middleware::Logger::default()) // enable logger .wrap(middleware::Logger::default()) // enable logger
.wrap(actix_flash::Flash::default())
.configure(init) .configure(init)
.service(fs::Files::new("/static", "./static").show_files_listing())
}); });
server = match listenfd.take_tcp_listener(0)? { server = match listenfd.take_tcp_listener(0)? {

View File

@ -1,3 +0,0 @@
HOST=127.0.0.1
PORT=8000
DATABASE_URL="mysql://root:root@localhost/actix_example"

View File

@ -1,5 +1,5 @@
[package] [package]
name = "sea-orm-actix-example" name = "sea-orm-actix-4-beta-example"
version = "0.1.0" version = "0.1.0"
authors = ["Sam Samai <sam@studio2pi.com.au>"] authors = ["Sam Samai <sam@studio2pi.com.au>"]
edition = "2021" edition = "2021"
@ -9,15 +9,15 @@ publish = false
members = [".", "entity", "migration"] members = [".", "entity", "migration"]
[dependencies] [dependencies]
actix-http = "2" actix-files = "0.6"
actix-web = "3" actix-http = "3"
actix-flash = "0.2" actix-rt = "2.7"
actix-files = "0.5" actix-service = "2"
futures = { version = "^0.3" } actix-web = "4"
futures-util = { version = "^0.3" }
tera = "1.8.0" tera = "1.15.0"
dotenv = "0.15" dotenv = "0.15"
listenfd = "0.3.3" listenfd = "0.5"
serde = "1" serde = "1"
tracing-subscriber = { version = "0.3", features = ["env-filter"] } tracing-subscriber = { version = "0.3", features = ["env-filter"] }
entity = { path = "entity" } entity = { path = "entity" }

View File

@ -1,6 +1,6 @@
![screenshot](Screenshot.png) ![screenshot](Screenshot.png)
# Actix with SeaORM example app # Actix 4 with SeaORM example app
1. Modify the `DATABASE_URL` var in `.env` to point to your chosen database 1. Modify the `DATABASE_URL` var in `.env` to point to your chosen database

View File

@ -17,7 +17,7 @@ version = "^0.7.0"
features = [ features = [
"macros", "macros",
"debug-print", "debug-print",
"runtime-async-std-native-tls", "runtime-actix-native-tls",
"sqlx-mysql", "sqlx-mysql",
# "sqlx-postgres", # "sqlx-postgres",
# "sqlx-sqlite", # "sqlx-sqlite",

View File

@ -1,6 +1,6 @@
use actix_files as fs; use actix_files::Files as Fs;
use actix_web::{ use actix_web::{
error, get, middleware, post, web, App, Error, HttpRequest, HttpResponse, HttpServer, Result, error, get, middleware, post, web, App, Error, HttpRequest, HttpResponse, HttpServer, Result
}; };
use entity::post; use entity::post;
@ -21,6 +21,7 @@ struct AppState {
templates: tera::Tera, templates: tera::Tera,
conn: DatabaseConnection, conn: DatabaseConnection,
} }
#[derive(Debug, Deserialize)] #[derive(Debug, Deserialize)]
pub struct Params { pub struct Params {
page: Option<usize>, page: Option<usize>,
@ -34,11 +35,7 @@ struct FlashData {
} }
#[get("/")] #[get("/")]
async fn list( async fn list(req: HttpRequest, data: web::Data<AppState>) -> Result<HttpResponse, Error> {
req: HttpRequest,
data: web::Data<AppState>,
opt_flash: Option<actix_flash::Message<FlashData>>,
) -> Result<HttpResponse, Error> {
let template = &data.templates; let template = &data.templates;
let conn = &data.conn; let conn = &data.conn;
@ -62,11 +59,6 @@ async fn list(
ctx.insert("posts_per_page", &posts_per_page); ctx.insert("posts_per_page", &posts_per_page);
ctx.insert("num_pages", &num_pages); ctx.insert("num_pages", &num_pages);
if let Some(flash) = opt_flash {
let flash_inner = flash.into_inner();
ctx.insert("flash", &flash_inner);
}
let body = template let body = template
.render("index.html.tera", &ctx) .render("index.html.tera", &ctx)
.map_err(|_| error::ErrorInternalServerError("Template error"))?; .map_err(|_| error::ErrorInternalServerError("Template error"))?;
@ -87,7 +79,7 @@ async fn new(data: web::Data<AppState>) -> Result<HttpResponse, Error> {
async fn create( async fn create(
data: web::Data<AppState>, data: web::Data<AppState>,
post_form: web::Form<post::Model>, post_form: web::Form<post::Model>,
) -> actix_flash::Response<HttpResponse, FlashData> { ) -> Result<HttpResponse, Error> {
let conn = &data.conn; let conn = &data.conn;
let form = post_form.into_inner(); let form = post_form.into_inner();
@ -101,12 +93,9 @@ async fn create(
.await .await
.expect("could not insert post"); .expect("could not insert post");
let flash = FlashData { Ok(HttpResponse::Found()
kind: "success".to_owned(), .append_header(("location", "/"))
message: "Post successfully added.".to_owned(), .finish())
};
actix_flash::Response::with_redirect(flash, "/")
} }
#[get("/{id}")] #[get("/{id}")]
@ -134,7 +123,7 @@ async fn update(
data: web::Data<AppState>, data: web::Data<AppState>,
id: web::Path<i32>, id: web::Path<i32>,
post_form: web::Form<post::Model>, post_form: web::Form<post::Model>,
) -> actix_flash::Response<HttpResponse, FlashData> { ) -> Result<HttpResponse, Error> {
let conn = &data.conn; let conn = &data.conn;
let form = post_form.into_inner(); let form = post_form.into_inner();
@ -147,19 +136,13 @@ async fn update(
.await .await
.expect("could not edit post"); .expect("could not edit post");
let flash = FlashData { Ok(HttpResponse::Found()
kind: "success".to_owned(), .append_header(("location", "/"))
message: "Post successfully updated.".to_owned(), .finish())
};
actix_flash::Response::with_redirect(flash, "/")
} }
#[post("/delete/{id}")] #[post("/delete/{id}")]
async fn delete( async fn delete(data: web::Data<AppState>, id: web::Path<i32>) -> Result<HttpResponse, Error> {
data: web::Data<AppState>,
id: web::Path<i32>,
) -> actix_flash::Response<HttpResponse, FlashData> {
let conn = &data.conn; let conn = &data.conn;
let post: post::ActiveModel = Post::find_by_id(id.into_inner()) let post: post::ActiveModel = Post::find_by_id(id.into_inner())
@ -171,12 +154,9 @@ async fn delete(
post.delete(conn).await.unwrap(); post.delete(conn).await.unwrap();
let flash = FlashData { Ok(HttpResponse::Found()
kind: "success".to_owned(), .append_header(("location", "/"))
message: "Post successfully deleted.".to_owned(), .finish())
};
actix_flash::Response::with_redirect(flash, "/")
} }
#[actix_web::main] #[actix_web::main]
@ -191,20 +171,23 @@ async fn main() -> std::io::Result<()> {
let port = env::var("PORT").expect("PORT is not set in .env file"); let port = env::var("PORT").expect("PORT is not set in .env file");
let server_url = format!("{}:{}", host, port); let server_url = format!("{}:{}", host, port);
// create post table if not exists // establish connection to database and apply migrations
// -> create post table if not exists
let conn = sea_orm::Database::connect(&db_url).await.unwrap(); let conn = sea_orm::Database::connect(&db_url).await.unwrap();
Migrator::up(&conn, None).await.unwrap(); Migrator::up(&conn, None).await.unwrap();
// load tera templates and build app state
let templates = Tera::new(concat!(env!("CARGO_MANIFEST_DIR"), "/templates/**/*")).unwrap(); let templates = Tera::new(concat!(env!("CARGO_MANIFEST_DIR"), "/templates/**/*")).unwrap();
let state = AppState { templates, conn }; let state = AppState { templates, conn };
// create server and try to serve over socket if possible
let mut listenfd = ListenFd::from_env(); let mut listenfd = ListenFd::from_env();
let mut server = HttpServer::new(move || { let mut server = HttpServer::new(move || {
App::new() App::new()
.data(state.clone()) .service(Fs::new("/static", "./static"))
.app_data(web::Data::new(state.clone()))
.wrap(middleware::Logger::default()) // enable logger .wrap(middleware::Logger::default()) // enable logger
.wrap(actix_flash::Flash::default())
.configure(init) .configure(init)
.service(fs::Files::new("/static", "./static").show_files_listing())
}); });
server = match listenfd.take_tcp_listener(0)? { server = match listenfd.take_tcp_listener(0)? {