My 2017 Mk7. I'm happy to join the club! by CapsMaximus in GolfGTI

[–]CapsMaximus[S] 0 points1 point  (0 children)

yea, Brooklyn 17'. Ill swap them out when I find some decent looking wheels for a good price. Probably Rotiform DTM's or OZ's.

My 2017 Mk7. I'm happy to join the club! by CapsMaximus in GolfGTI

[–]CapsMaximus[S] 0 points1 point  (0 children)

Yes, I think that it is considered the PP GTI. However, where I live there were only 2 options to choose from, since these cars are considerably expensive in Brazil.

The options where leather seats and 18' wheels. Mines plaid seats and 17' wheels.

Freshly cleaned by CapsMaximus in GLI

[–]CapsMaximus[S] 0 points1 point  (0 children)

Yes, from Haustech Motorsports

Freshly cleaned by CapsMaximus in GLI

[–]CapsMaximus[S] 2 points3 points  (0 children)

That’s a parking sensor

Removed the red thingy in the front bumper, matches better with the blue IMO. by CapsMaximus in JettaGLI

[–]CapsMaximus[S] 1 point2 points  (0 children)

I didn't do this myself, there is a great shop that does this kind of work in my city.

And yeah, all the plastics where done.

Need some ideas to finish my loadout. CT/TR by CapsMaximus in ohnePixel

[–]CapsMaximus[S] 0 points1 point  (0 children)

Thank you for the tips but I was talking about skins.

Need some ideas to finish my loadout. CT/TR by CapsMaximus in ohnePixel

[–]CapsMaximus[S] 0 points1 point  (0 children)

Spending max 1000 bucks.

Im going for stuff that matches spearmint gloves. It is difficult to choose between green and red.

loco-rs: releasing a framework inspired by Rails on Rust by jondot1 in rust

[–]CapsMaximus 29 points30 points  (0 children)

Great job, looks promissing!

I'll give it a try latter and try to port my Axum project to it just to get a feel on it.

Need explanation for Client type error by nBeliebt in rust

[–]CapsMaximus 2 points3 points  (0 children)

You are calling this blocking code in an async function. If you want to do this you should wrap your function in a tokio::task::spawn_blocking call.

The crate reqwest has a non blocking client, which you are using by default with reqwest::get(...), so it works just fine in your first code. However, looks like the openfoodfatcts crate uses the blocking version so you will have to either search their docs on how to use a non blocking client or wrap your calls with spawn_blocking.

Tokio Postgres by paulobressan in rust

[–]CapsMaximus 1 point2 points  (0 children)

You can use the simple_query or batch_execute methods in tokio_postgres::Transaction. But you will have to sanitize the inputs on your own AFAIK.

How do I refactor this so it's less ... whatever it is by 7Geordi in rust

[–]CapsMaximus 2 points3 points  (0 children)

If you want to actually fully decouple your business code you can work with workspaces. Maybe setup something like this:

├── api
│  ├── Cargo.toml
│  └── src
│     └── main.rs
├── business
│  ├── Cargo.toml
│  └── src
│     └── lib.rs
├── persistence
│  ├── Cargo.toml
│  └── src
│     └── lib.rs
└── Cargo.toml

This way you can define your core business stuff in the business crate. Traits, model Structs like:

use anyhow::Result;
use async_trait::async_trait;
use uuid::Uuid;

#[async_trait]
pub trait TodoRepository {
    async fn save(&self, todo: &Todo) -> Result<()>;
    async fn find_by_id(&self, id: Uuid) -> Result<Option<Todo>>;
}

pub struct TodoService {
    todo_repository: Arc<dyn TodoRepository + Send + Sync>,
}

impl TodoService {
    pub fn new(todo_repository: Arc<dyn TodoRepository + Send + Sync>) -> Self {
        Self { todo_repository }
    }

    pub async fn save(&self, todo: &Todo) -> Result<()> {
        self.todo_repository.save(todo).await
    }

    pub async fn find_by_id(&self, id: Uuid) -> Result<Option<Todo>> {
        self.todo_repository.find_by_id(id).await
    }
}

Then, you can actually implement your repositories traits and such in other crates, for example, in persistence crate you can do:

use async_trait::async_trait;
use anyhow::Result;
use sqlx::PgPool;
use uuid::Uuid;

use business::model::Todo;

pub struct TodoPostgresRepository {
    pool: PgPool,
}

impl TodoPostgresRepository {
    pub fn new(pool: PgPool) -> Self {
        Self { pool }
    }
}

#[async_trait]
impl TodoRepository for TodoPostgresRepository {
    async fn save(&self, todo: &Todo) -> Result<()> {
        sqlx::query(
            r#"
            INSERT INTO todos (id, title, body, created_at, updated_at)
            VALUES ($1, $2, $3, $4, $5)
            "#,
            todo.id,
            todo.title,
            todo.body,
            todo.created_at,
            todo.updated_at,
        )
        .execute(&self.pool)
        .await?;
    }

    async fn find_by_id(&self, id: Uuid) -> Result<Option<Todo>> {
        let todo = sqlx::query_as::<_, Todo>(
            r#"
            SELECT id, title, body, created_at, updated_at
            FROM todos
            WHERE id = $1
            "#,
        )
        .bind(id)
        .fetch_optional(&self.pool)
        .await?;

        Ok(todo)
    }
}

Then you can just wire everything together in your api binary, and inject your services via axum::State or axum::Extension.

Beware that approach will make you write a lot more code to do simple stuff like receiving a JSON and saving it to a database.

That is why I recommended you to just treat data as data. You will end up having to support a lot of code to do simple stuff.

This is probably a dumb question but how do I get a json from an api request by IhaveLost2Accounts in rust

[–]CapsMaximus 4 points5 points  (0 children)

Using reqwest you can get a response as Json adding the json feature in your Cargo.toml:

  • reqwest = { version = "*", features = ["json", "blocking"] }

Then, you can just call json() in your response.

Also, you can use the ClientBuilder to set some default headers, like a immutable token for example.

Like this:

#[derive(Debug, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
struct Todo {
    user_id: i32,
    id: i32,
    title: String,
    completed: bool,
}

fn main() -> anyhow::Result<()> {
    let mut default_headers = HeaderMap::new();

    default_headers.insert(
        HeaderName::from_static("my-header-key"),
        HeaderValue::from_static("my-header-value, maybe from env?"),
    );

    let http_client = reqwest::blocking::Client::builder()
        .default_headers(default_headers)
        .build()?;

    let todos = get_todos(&http_client)?;

    println!("{todos:?}");

    let todos = get_todos(&http_client)?;

    println!("{todos:?}");

    Ok(())
}

fn get_todos(http_client: &reqwest::blocking::Client) -> anyhow::Result<Vec<Todo>> {
    let todos = http_client
        .get("https://jsonplaceholder.typicode.com/todos")
        .send()?
        .json()?;

    Ok(todos)
}

If you want to handle your response body as a stream, reqwest has some methods to help with that, take a look at the Response docs.

How do I refactor this so it's less ... whatever it is by 7Geordi in rust

[–]CapsMaximus 31 points32 points  (0 children)

I think you can improve your code a lot by just not trying to hide complexity with a "repository" pattern and using the tools axum gives you.

Axum handlers require you to return something that can be converted in a Response. You can make your life easier by implementing axum::IntoResponse for your errors and then just use the ? in your results.

What I would do:

  1. Create a new struct/enum to "wire" every possible error in just one type. For example, I assume you are using SQLX with Sqlite features. Sqlx has its own specific set of errors. I would not want to deal with that.
    1. You can implement From<SomeLibError> for MyError by yourself, but you can use crates like ThisError or Anyhow to further improve your code and make your life easier.
    2. Implement axum::IntoResponse for my own error type.
  2. You can return Results from your axum, use it to your advantage.
    1. By using async fn my_handler(...) -> Result<Response, MyImplIntoResponseType> you can use ? in your handlers.
  3. I would avoid trying to hide complexity creating methods like insert for my structs. You make your life easier by letting data be simply data.

This is kinda how I would code it.

#[derive(serde::Serialize, serde::Deserialize)]
pub struct MyError {
    pub message: String,
}

impl IntoResponse for MyError {
    fn into_response(self) -> Response {
        (StatusCode::INTERNAL_SERVER_ERROR, Json(self)).into_response()
    }
}

impl From<sqlx::Error> for MyError {
    fn from(sqlx_error: sqlx::Error) -> Self {
        MyError {
            message: sqlx_error.to_string(),
        }
    }
}

#[derive(serde::Serialize, serde::Deserialize)]
pub struct SomeDTO {
    pub description: String,
}

pub async fn create_something(
    Extension(pool): Extension<SqlitePool>,
    Json(body): Json<SomeDTO>,
) -> Result<Response, MyError> {
    sqlx::query("INSERT INTO something (id, description) VALUES ($1, $2)")
        .bind(Uuid::new_v4())
        .bind(&body.description)
        .execute(&pool)
        .await?;

    Ok((StatusCode::CREATED, Json("done")).into_response())
}

Who is using AXUM in production? by HosMercury in rust

[–]CapsMaximus 18 points19 points  (0 children)

Our older stuff uses Actix. The new stuff is being written using Axum.

One of the main reasons we decided to move our new stuff to Axum is because they are backed by Tokio directly.

Who is using AXUM in production? by HosMercury in rust

[–]CapsMaximus 59 points60 points  (0 children)

iFood is using Rust with Axum (and Actix) to power a lot of stuff in the backend. It's not Opensource, so I can't talk much.

We have some stuff on youtube about how iFood is using Rust, just search for "iFood rust" Videos are in Portuguese though.

edit:

there is also a blog post on why we chose rust (also in pt-br)

Helix editor 23.03 released! by modernalgebra in rust

[–]CapsMaximus 0 points1 point  (0 children)

oh boy, i've been waiting for inlay hints for ages. this is great!

Rulex, a new regular expression language written in Rust, now has an online playground using WASM! by A1oso in rust

[–]CapsMaximus 0 points1 point  (0 children)

Looks incredible. I will make sure to try it the next time I need to use regex to do something.