Skip to content

Commit

Permalink
Added derivable trait ErrorWithStatusCode to facilitate creating erro…
Browse files Browse the repository at this point in the history
…r responses.
  • Loading branch information
sammhicks committed Jan 20, 2025
1 parent d4acd96 commit bf13b4c
Show file tree
Hide file tree
Showing 15 changed files with 298 additions and 246 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## Unreleased

### Added

- Added derivable trait [`ErrorWithStatusCode`](https://docs.rs/picoserve/latest/picoserve/response/trait.ErrorWithStatusCode.html) to facilitate creating error responses. Deriving `ErrorWithStatusCode` also derives [`IntoResponse`](https://docs.rs/picoserve/latest/picoserve/response/trait.IntoResponse.html)

## [0.13.3] - 2024-12-26

### Fixed
Expand Down
2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
resolver = "2"
members = [
"picoserve",
"picoserve_derive",
"examples/chunked_response",
"examples/custom_extractor",
"examples/form",
Expand All @@ -25,4 +26,5 @@ exclude = [
anyhow = "1.0.86"
heapless = { version = "0.8.0", features = ["serde"] }
serde = { version = "1.0.204", features = ["derive"] }
thiserror = { version = "2.0.9", default-features = false }
tokio = { version = "1.38.1", features = ["rt", "io-util", "net", "time", "macros"] }
1 change: 1 addition & 0 deletions examples/custom_extractor/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,5 @@ edition = "2021"
anyhow = { workspace = true }
picoserve = { path = "../../picoserve", features = ["tokio"] }
serde = { workspace = true }
thiserror = { workspace = true }
tokio = { workspace = true }
46 changes: 7 additions & 39 deletions examples/custom_extractor/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,58 +4,26 @@ use std::time::Duration;

use picoserve::{
extract::FromRequest,
response::IntoResponse,
response::{ErrorWithStatusCode, IntoResponse},
routing::{get_service, post},
};

struct Number {
value: f32,
}

#[derive(Debug, thiserror::Error, ErrorWithStatusCode)]
#[status_code(BAD_REQUEST)]
enum BadRequest {
#[error("Read Error")]
#[status_code(INTERNAL_SERVER_ERROR)]
ReadError,
#[error("Request Body is not UTF-8: {0}")]
NotUtf8(core::str::Utf8Error),
#[error("Request Body is not a valid integer: {0}")]
BadNumber(core::num::ParseFloatError),
}

impl IntoResponse for BadRequest {
async fn write_to<
R: picoserve::io::Read,
W: picoserve::response::ResponseWriter<Error = R::Error>,
>(
self,
connection: picoserve::response::Connection<'_, R>,
response_writer: W,
) -> Result<picoserve::ResponseSent, W::Error> {
match self {
BadRequest::ReadError => {
(
picoserve::response::StatusCode::BAD_REQUEST,
format_args!("Read Error"),
)
.write_to(connection, response_writer)
.await
}
BadRequest::NotUtf8(err) => {
(
picoserve::response::StatusCode::BAD_REQUEST,
format_args!("Request Body is not UTF-8: {err}"),
)
.write_to(connection, response_writer)
.await
}
BadRequest::BadNumber(err) => {
(
picoserve::response::StatusCode::BAD_REQUEST,
format_args!("Request Body is not a valid integer: {err}"),
)
.write_to(connection, response_writer)
.await
}
}
}
}

impl<'r, State> FromRequest<'r, State> for Number {
type Rejection = BadRequest;

Expand Down
3 changes: 2 additions & 1 deletion examples/server_sent_events/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,5 @@ edition = "2021"
[dependencies]
anyhow = { workspace = true }
picoserve = { path = "../../picoserve", features = ["tokio"] }
tokio = { workspace = true, features = [ "sync" ] }
thiserror = { workspace = true }
tokio = { workspace = true, features = ["sync"] }
31 changes: 5 additions & 26 deletions examples/server_sent_events/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,40 +1,19 @@
use std::time::Duration;

use picoserve::{
response::{self, StatusCode},
response::{self, ErrorWithStatusCode, StatusCode},
routing::{get, get_service, post},
ResponseSent,
};

#[derive(Debug, thiserror::Error, ErrorWithStatusCode)]
#[status_code(BAD_REQUEST)]
enum NewMessageRejection {
#[error("Read Error")]
ReadError,
#[error("Body is not UTF-8: {0}")]
NotUtf8(std::str::Utf8Error),
}

impl response::IntoResponse for NewMessageRejection {
async fn write_to<R: picoserve::io::Read, W: response::ResponseWriter<Error = R::Error>>(
self,
connection: response::Connection<'_, R>,
response_writer: W,
) -> Result<ResponseSent, W::Error> {
match self {
NewMessageRejection::ReadError => {
(StatusCode::BAD_REQUEST, "Read Error")
.write_to(connection, response_writer)
.await
}
NewMessageRejection::NotUtf8(err) => {
(
StatusCode::BAD_REQUEST,
format_args!("Body is not UTF-8: {err}\n"),
)
.write_to(connection, response_writer)
.await
}
}
}
}

struct NewMessage(String);

impl<'r, State> picoserve::extract::FromRequest<'r, State> for NewMessage {
Expand Down
2 changes: 2 additions & 0 deletions picoserve/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,11 @@ futures-util = { version = "0.3.28", default-features = false }
heapless = { version = "0.8.0", features = ["serde"] }
lhash = { version = "1.0.1", features = ["sha1"] }
log = { version = "0.4.19", optional = true, default-features = false }
picoserve_derive = { path = "../picoserve_derive" }
ryu = "1.0.14"
serde = { version = "1.0.171", default-features = false, features = ["derive"] }
serde-json-core = "0.6.0"
thiserror = { version = "2.0.9", default-features = false }
tokio = { version = "1.32.0", optional = true, features = ["io-util", "net", "time"] }

[features]
Expand Down
Loading

0 comments on commit bf13b4c

Please sign in to comment.