Skip to content

Commit

Permalink
Merge branch 'master' into fix/loco-rs#1119-csr-remove-unecessary-code
Browse files Browse the repository at this point in the history
  • Loading branch information
kaplanelad authored Jan 14, 2025
2 parents 9c472fa + eb7ea64 commit 4bdbfac
Show file tree
Hide file tree
Showing 24 changed files with 568 additions and 9 deletions.
4 changes: 4 additions & 0 deletions .github/workflows/loco-gen-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,11 @@ on:
push:
branches:
- master
paths:
- "loco-gen/**"
pull_request:
paths:
- "loco-gen/**"

env:
RUST_TOOLCHAIN: stable
Expand Down
4 changes: 4 additions & 0 deletions .github/workflows/loco-gen-e2e.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,11 @@ on:
push:
branches:
- master
paths:
- "loco-gen/**"
pull_request:
paths:
- "loco-gen/**"

env:
RUST_TOOLCHAIN: stable
Expand Down
68 changes: 68 additions & 0 deletions .github/workflows/loco-rs-ci-sanity.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
# To optimize CI runtime:
# A simpler "sanity check" workflow is introduced.
# This workflow only runs if changes in the PR do NOT include
# the `loco-gen` or `loco-new` paths.
# (When changes are made to `loco-gen` or `loco-new`,
# we run comprehensive tests to validate every generator command
# and template option.)

# Purpose of the sanity check:
# It performs basic validation by comparing the local changes
# against the templates.
# If any breaking changes are detected in the templates,
# the sanity check will fail, signaling an issue.

name: "[loco_rs:sanity]"

on:
push:
branches:
- master
paths-ignore:
- "loco-gen/**"
- "loco-new/**"
pull_request:
paths-ignore:
- "loco-gen/**"
- "loco-new/**"

env:
RUST_TOOLCHAIN: stable
TOOLCHAIN_PROFILE: minimal

jobs:
sanity:
runs-on: ubuntu-latest

permissions:
contents: read

steps:
- name: Checkout the code
uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
with:
toolchain: ${{ env.RUST_TOOLCHAIN }}
- name: Setup Rust cache
uses: Swatinem/rust-cache@v2

- name: Install seaorm cli
run: cargo install sea-orm-cli

- run: cargo install --path loco-new

- run: |
loco new -n myappdb --db sqlite --bg async --assets serverside -a
cd myappdb
cargo check
env:
LOCO_DEV_MODE_PATH: ${{ github.workspace }}
- run: |
loco new -n myappnodb --db none --bg none --assets none -a
cd myappdb
cargo check
env:
LOCO_DEV_MODE_PATH: ${{ github.workspace }}
22 changes: 21 additions & 1 deletion .github/workflows/loco-rs-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,30 @@ jobs:
command: clippy
args: --all-features -- -D warnings -W clippy::pedantic -W clippy::nursery -W rust-2018-idioms

test:
check:
needs: [style]
runs-on: ubuntu-latest

permissions:
contents: read

steps:
- name: Checkout the code
uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
with:
toolchain: ${{ env.RUST_TOOLCHAIN }}
- name: Setup Rust cache
uses: Swatinem/rust-cache@v2
- uses: taiki-e/install-action@v2
with:
tool: cargo-hack
- run: cargo hack check --each-feature

test:
needs: [check, style]
runs-on: ubuntu-latest

permissions:
contents: read

Expand Down
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,18 @@

## Unreleased

* fix: bump shuttle to 0.51.0. [https://github.com/loco-rs/loco/pull/1169](https://github.com/loco-rs/loco/pull/1169)
* Return 422 status code for JSON rejection errors. [https://github.com/loco-rs/loco/pull/1173](https://github.com/loco-rs/loco/pull/1173)
* Address clippy warnings for Rust stable 1.84. [https://github.com/loco-rs/loco/pull/1168](https://github.com/loco-rs/loco/pull/1168)
* Bump shuttle to 0.51.0. [https://github.com/loco-rs/loco/pull/1169](https://github.com/loco-rs/loco/pull/1169)
* return 422 status code for JSON rejection errors. [https://github.com/loco-rs/loco/pull/1173](https://github.com/loco-rs/loco/pull/1173)
* return json validation details response. [https://github.com/loco-rs/loco/pull/1174](https://github.com/loco-rs/loco/pull/1174)
* fix example command after generating schedule. [https://github.com/loco-rs/loco/pull/1176](https://github.com/loco-rs/loco/pull/1176)
* fixed independent features. [https://github.com/loco-rs/loco/pull/1177](https://github.com/loco-rs/loco/pull/1177)


## v0.14

* feat: smart migration generator. you can now generate migration based on naming them for creating a table, adding columns, references, join tables and more. [https://github.com/loco-rs/loco/pull/1086](https://github.com/loco-rs/loco/pull/1086)
* feat: `cargo loco routes` will now pretty-print routes
* fix: guard jwt error behind feature flag. [https://github.com/loco-rs/loco/pull/1032](https://github.com/loco-rs/loco/pull/1032)
Expand Down
3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ lettre = { version = "0.11.4", default-features = false, features = [
include_dir = "0.7.3"
thiserror = { workspace = true }
tracing = { workspace = true }
tracing-subscriber = { version = "0.3.16", features = ["env-filter"] }
tracing-subscriber = { version = "0.3.16", features = ["env-filter", "json"] }
tracing-appender = "0.2.3"

duct = { version = "0.13.6" }
Expand Down Expand Up @@ -146,6 +146,7 @@ english-to-cron = { version = "0.1.2" }
# bg_sqlt: sqlite workers
# bg_pg: postgres workers
sqlx = { version = "0.8.2", default-features = false, features = [
"json",
"postgres",
"chrono",
"sqlite",
Expand Down
64 changes: 64 additions & 0 deletions docs-site/content/docs/the-app/controller.md
Original file line number Diff line number Diff line change
Expand Up @@ -764,6 +764,70 @@ impl Hooks for App {
}
```

# Request Validation
`JsonValidate` extractor simplifies input [validation](https://github.com/Keats/validator) by integrating with the validator crate. Here's an example of how to validate incoming request data:

### Define Your Validation Rules
```rust
use axum::debug_handler;
use loco_rs::prelude::*;
use serde::Deserialize;
use validator::Validate;

#[derive(Debug, Deserialize, Validate)]
pub struct DataParams {
#[validate(length(min = 5, message = "custom message"))]
pub name: String,
#[validate(email)]
pub email: String,
}
```
### Create a Handler with Validation
```rust
use axum::debug_handler;
use loco_rs::prelude::*;

#[debug_handler]
pub async fn index(
State(_ctx): State<AppContext>,
JsonValidate(params): JsonValidate<DataParams>,
) -> Result<Response> {
format::empty()
}
```
Using the `JsonValidate` extractor, Loco automatically performs validation on the DataParams struct:
* If validation passes, the handler continues execution with params.
* If validation fails, a 400 Bad Request response is returned.

### Returning Validation Errors as JSON
If you'd like to return validation errors in a structured JSON format, use `JsonValidateWithMessage` instead of `JsonValidate`. The response format will look like this:

```json
{
"errors": {
"email": [
{
"code": "email",
"message": null,
"params": {
"value": "ad"
}
}
],
"name": [
{
"code": "length",
"message": "custom message",
"params": {
"min": 5,
"value": "d"
}
}
]
}
}
```

# Pagination

In many scenarios, when querying data and returning responses to users, pagination is crucial. In `Loco`, we provide a straightforward method to paginate your data and maintain a consistent pagination response schema for your API responses.
Expand Down
2 changes: 1 addition & 1 deletion loco-gen/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ pub struct GenerateResults {
rrgen: Vec<rrgen::GenResult>,
local_templates: Vec<PathBuf>,
}
const DEPLOYMENT_SHUTTLE_RUNTIME_VERSION: &str = "0.46.0";
const DEPLOYMENT_SHUTTLE_RUNTIME_VERSION: &str = "0.51.0";

const DEPLOYMENT_OPTIONS: &[(&str, DeploymentKind)] = &[
("Docker", DeploymentKind::Docker),
Expand Down
10 changes: 9 additions & 1 deletion loco-gen/src/templates/deployment/shuttle/config.t
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,12 @@ to: "Shuttle.toml"
skip_exists: true
message: "Shuttle.toml file created successfully"
---
name = "{{pkg_name}}"
[deploy]
include = [
"config/production.yaml"
]

[build]
assets = [
"config/production.yaml"
]
7 changes: 6 additions & 1 deletion loco-gen/src/templates/deployment/shuttle/shuttle.t
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,12 @@ async fn main(
shuttle_runtime::Environment::Local => Environment::Development,
shuttle_runtime::Environment::Deployment => Environment::Production,
};
let boot_result = create_app::<App{% if with_db %}, Migrator{% endif %}>(StartMode::ServerOnly, &environment)

let config = environment
.load()
.expect("Failed to load configuration from the environment");

let boot_result = create_app::<App{% if with_db %}, Migrator{% endif %}>(StartMode::ServerOnly, &environment, config)
.await
.unwrap();

Expand Down
2 changes: 1 addition & 1 deletion loco-gen/src/templates/scheduler/scheduler.t
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
to: "config/scheduler.yaml"
skip_exists: true
message: "A Scheduler job configuration was added successfully. Run with `cargo loco run scheduler --list`."
message: "A Scheduler job configuration was added successfully. Run with `cargo loco scheduler --list`."

---
output: stdout
Expand Down
70 changes: 70 additions & 0 deletions loco-gen/tests/templates/deployment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,3 +99,73 @@ fn can_generate_nginx() {
.expect("nginx config missing")
);
}

#[test]
fn can_generate_shuttle() {
let mut settings = insta::Settings::clone_current();
settings.set_prepend_module_to_snapshot(false);
settings.set_snapshot_suffix("deployment");
let _guard = settings.bind_to_scope();

let component = Component::Deployment {
kind: DeploymentKind::Shuttle,
fallback_file: None,
asset_folder: None,
host: "localhost".to_string(),
port: 8080,
};

let tree_fs = tree_fs::TreeBuilder::default()
.drop(true)
.add(
".cargo/config.toml",
r#"[alias]
loco = "run --"
loco-tool = "run --"
playground = "run --example playground"
"#,
)
.add(
"Cargo.toml",
r"
[dependencies]
[dev-dependencies]
",
)
.create()
.unwrap();
let rrgen = RRgen::with_working_dir(&tree_fs.root);

let gen_result = generate(
&rrgen,
component,
&AppInfo {
app_name: "tester".to_string(),
},
)
.expect("Generation failed");

assert_eq!(
collect_messages(&gen_result),
r"* Shuttle.toml file created successfully
* Shuttle deployment ready do use
"
);
assert_snapshot!(
"generate[shuttle.rs]",
fs::read_to_string(tree_fs.root.join("src").join("bin").join("shuttle.rs"))
.expect("shuttle rs missing")
);
assert_snapshot!(
"inject[.config_toml]",
fs::read_to_string(tree_fs.root.join(".cargo").join("config.toml"))
.expect(".cargo/config.toml not exists")
);
assert_snapshot!(
"inject[cargo_toml]",
fs::read_to_string(tree_fs.root.join("Cargo.toml")).expect("cargo.toml not exists")
);
}
2 changes: 1 addition & 1 deletion loco-gen/tests/templates/scheduler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ fn can_generate() {

assert_eq!(
collect_messages(&gen_result),
r"* A Scheduler job configuration was added successfully. Run with `cargo loco run scheduler --list`.
r"* A Scheduler job configuration was added successfully. Run with `cargo loco scheduler --list`.
"
);

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
---
source: loco-gen/tests/templates/deployment.rs
expression: "fs::read_to_string(tree_fs.root.join(\"src\").join(\"bin\").join(\"shuttle.rs\")).expect(\"shuttle rs missing\")"
---
use loco_rs::boot::{create_app, StartMode};
use loco_rs::environment::Environment;
use tester::app::App;
use migration::Migrator;
use shuttle_runtime::DeploymentMetadata;

#[shuttle_runtime::main]
async fn main(
#[shuttle_shared_db::Postgres] conn_str: String,
#[shuttle_runtime::Metadata] meta: DeploymentMetadata,
) -> shuttle_axum::ShuttleAxum {
std::env::set_var("DATABASE_URL", conn_str);
let environment = match meta.env {
shuttle_runtime::Environment::Local => Environment::Development,
shuttle_runtime::Environment::Deployment => Environment::Production,
};

let config = environment
.load()
.expect("Failed to load configuration from the environment");

let boot_result = create_app::<App, Migrator>(StartMode::ServerOnly, &environment, config)
.await
.unwrap();

let router = boot_result.router.unwrap();
Ok(router.into())
}
Loading

0 comments on commit 4bdbfac

Please sign in to comment.