https://github.com/stifskere/actix_error_proc
A small crate to integrate thiserror with actix_web.
https://github.com/stifskere/actix_error_proc
actix actixweb error macros thiserror
Last synced: 3 months ago
JSON representation
A small crate to integrate thiserror with actix_web.
- Host: GitHub
- URL: https://github.com/stifskere/actix_error_proc
- Owner: stifskere
- License: mit
- Created: 2025-02-04T11:47:11.000Z (8 months ago)
- Default Branch: main
- Last Pushed: 2025-05-11T11:58:29.000Z (5 months ago)
- Last Synced: 2025-05-11T12:31:51.962Z (5 months ago)
- Topics: actix, actixweb, error, macros, thiserror
- Language: Rust
- Homepage: https://crates.io/crates/actix_error_proc
- Size: 183 KB
- Stars: 6
- Watchers: 1
- Forks: 1
- Open Issues: 0
-
Metadata Files:
- Readme: readme.md
- License: license
Awesome Lists containing this project
README
# actix_error_proc
`actix_error_proc` is a small library to integrate `thiserror` into `actix_web` routes
with procedural macros.This library has two main macros as well as a `thiserror` re export under the `thiserror` feature.
## `ActixError`
This macro is used together with `thiserror::Error` and it allows the user
to add a few more attributes to the error enumerable. This macro in reality
it simply implements `Into` and `Into`
for the sake of it being used in routes and collectors.A basic usage of this macro looks like this
```rust
use actix_error_proc::{ActixError, Error}; // Error is a thiserror re export.#[derive(ActixError, Error, Debug)]
enum SomeError {
#[error("Couldn't parse http body.")]
#[http_status(BadRequest)]
InvalidBody,// if no attribute is set the default is InternalServerError.
#[error("A database error occurred: {0:#}")]
DatabaseError(#[from] /* ... */)
}
```By default the response is simply the status code and the `#[error("...")]` format
as a body. But you can change that with the `transformer`.There is another attribute you can add called `actix_error` at the enumerable level
that lets you change how the response will look, for now it only has the `transformer`
variable, but in a future it might have more things.An example usage of the `transformer` variable looks like this
```rust
use actix_error_proc::{ActixError, Error}; // Error is a thiserror re export.// This should not throw any error, the errors should be handled
// at the request level.
fn transform_error(mut res: HttpResponseBuilder, fmt: String) -> HttpResponse {
res
.insert_header(("Test", "This is a test header"))
.json(json!({"error": fmt})) // by default the response is the raw string.
}#[derive(ActixError, Error, Debug)]
#[actix_error(transformer = "transform_error")] // reference `transform_error` here.
enum SomeError {
// ...
}
```All of this is to be used with the `proof_route` attribute.
## `proof_route`
This attribute wraps an `actix_web` route changing it's result into a `Result>`
where E is your custom enumerable that implements `Into` because of the `ActixError` derive macro.There is a type alias for that Result which is `actix_error_proc::HttpResult`.
An example usage of the `proof_route` procedural macro look like this
```rust
use actix_error_proc::{ActixError, Error, HttpResult}; // Error is a thiserror re export.
use crate::models::user::User;
use actix_web::{main, App, HttpServer}
use serde_json::{from_slice, Error as JsonError};
use std::io::Error as IoError;// assuming we have a wrapped enum
#[derive(ActixError, Error, Debug)]
enum SomeError {
#[error("The body could not be parsed.")]
#[status_code(BadRequest)]
InvalidBody(#[from] JsonError)
}#[proof_route(post("/users"))]
async fn some_route(body: Bytes) -> HttpResult {
let user: User = from_slice(body)?; // notice the use of `?`.// Do something with the user.
Ok(HttpResponse::NoContent()) // return Ok if everything went fine.
}async fn main() -> IoError {
HttpServer::new(|| {
App::new()
.service(some_route) // we can register the route normally.
})
.bind(("0.0.0.0", 8080))?
.run()
.await
}
```There is an extra attribute we can add to route collectors to override
it's error status code, in the case we don't want the original status code
or we didn't create the collector and the original error does not match our
expectations we can use `#[or]`, which lets us specify an error branch
from any type instance that implements `Into`.```rust
#[proof_route(post("/"))]
async fn route(#[or(SomeError::InvalidUser)] user: Json) // ...
```In this case if `Json` fails while collecting from the http request
whatever `>.into()` returns
will be passed directly as a response for the route.If you don't add the attribute, the request will be collected as normal and in the
case of any error the original error implementation for that collector will
be applied.
## ContributingBefore making a blind pull request please, open an issue we can talk about it and
then if it's necessary you can make a pull request, I actively maintain this project
so I'll read all the issues when possible.You can also email me at `esteve@memw.es`. Thanks.