Practical Rust Web Development - Macros
Tags: rust, actixweb, macros
Published: 2019-07-20 15:35:28

One thing someone might notice is how boilerplate we need to write comparing to other programming languages, specially for the web, however, there is some code we need to write, like types, that many of us agree are necessary to improve the development process.

We can reduce code in other areas and we have macros that allows us to do that, however we need to be careful, because macros can make our code hard to maintain. So, use macros sparingly.

Let's create a macro to reduce the amount of code we write for a handler. At first it might seem overwhelming, but, once you understand them, they can be a powerful tool.

`src/handlers/function_handler.rs`:

```rust

macro_rules! function_handler {
    ( $handler_name:ident ($($arg:ident:$typ:ty),*) -> $body:expr) => {
        pub fn $handler_name(user: LoggedUser, pool: web::Data<PgPool>, $($arg:$typ,)*) 
            -> impl Future<Item = HttpResponse, Error = actix_web::Error>
        {
            web::block(move || {
                let pg_pool = pool
                    .get()
                    .map_err(|_| {
                        crate::errors::MyStoreError::PGConnectionError
                    })?;
                $body(user, pg_pool)
            })
            .then(|res| match res {
                Ok(data) => Ok(HttpResponse::Ok().json(data)),
                Err(_) => Ok(HttpResponse::InternalServerError().into()),
            })
        }
    };
}
```

We declare a macro with `macro_rules!`, you could even create new syntax with a macro, in our case we want to create handlers following the next syntax: `handler name (params) -> block of code`, that can be expressed in this way: `$handler_name:ident ($($arg:ident:$typ:ty),*) -> $body:expr`, `$handler_name` is an identifier, the name of our handler, then we pass the parameters, because we don't know how many of them are, we are separating them with a comma and use this syntax: `$(),*`, this is to tell Rust we have infinity amount of parameters. Now we need a way to tell Rust to split parameters from block of code, I'm using an arrow to achieve that.

We identify our closure as `$body` and then pass the parameters so we can use it in our handlers, specifically the logged user and the database connection.

Now compare this:

```rust
pub fn index(user: LoggedUser, pool: web::Data<PgPool>) 
    -> impl Future<Item = HttpResponse, Error = actix_web::Error> {
        web::block(move || {
            let pg_pool = pool
                .get()
                .map_err(|_| {
                    crate::errors::MyStoreError::PGConnectionError
                })?;
            PriceList::list(user.id, &pg_pool)
        })
        .then(|res| match res {
            Ok(data) => Ok(HttpResponse::Ok().json(data)),
            Err(error) => Err(actix_web::error::ErrorInternalServerError(error)),
        })
}
```

with this:

```rust
function_handler!(
    index () -> (|user: LoggedUser, pg_pool: PgPooledConnection| {
        PriceList::list(user.id, &pg_pool)
    })
);
```

Pretty cool, right?

Source code [here](https://github.com/practical-rust-web-development/mystore/tree/v7.0).