api: Make OutgoingResponse a supertrait of EndpointError
This commit is contained in:
parent
cc2f2a231b
commit
6585aeb628
@ -134,7 +134,9 @@ impl Response {
|
|||||||
#response_init_fields
|
#response_init_fields
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
match <#error_ty as #ruma_api::EndpointError>::try_from_response(response) {
|
match <#error_ty as #ruma_api::EndpointError>::try_from_http_response(
|
||||||
|
response
|
||||||
|
) {
|
||||||
Ok(err) => Err(#ruma_api::error::ServerError::Known(err).into()),
|
Ok(err) => Err(#ruma_api::error::ServerError::Known(err).into()),
|
||||||
Err(response_err) => {
|
Err(response_err) => {
|
||||||
Err(#ruma_api::error::ServerError::Unknown(response_err).into())
|
Err(#ruma_api::error::ServerError::Unknown(response_err).into())
|
||||||
|
@ -7,15 +7,21 @@ use std::{error::Error as StdError, fmt};
|
|||||||
use bytes::Buf;
|
use bytes::Buf;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
use crate::EndpointError;
|
use crate::{EndpointError, OutgoingResponse};
|
||||||
|
|
||||||
// FIXME when `!` becomes stable use it
|
// FIXME when `!` becomes stable use it
|
||||||
/// Default `EndpointError` for `ruma_api!` macro
|
/// Default `EndpointError` for `ruma_api!` macro
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
pub enum Void {}
|
pub enum Void {}
|
||||||
|
|
||||||
|
impl OutgoingResponse for Void {
|
||||||
|
fn try_into_http_response(self) -> Result<http::Response<Vec<u8>>, IntoHttpError> {
|
||||||
|
match self {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl EndpointError for Void {
|
impl EndpointError for Void {
|
||||||
fn try_from_response<T: Buf>(
|
fn try_from_http_response<T: Buf>(
|
||||||
_response: http::Response<T>,
|
_response: http::Response<T>,
|
||||||
) -> Result<Self, ResponseDeserializationError> {
|
) -> Result<Self, ResponseDeserializationError> {
|
||||||
Err(ResponseDeserializationError::none())
|
Err(ResponseDeserializationError::none())
|
||||||
|
@ -214,17 +214,6 @@ pub mod exports {
|
|||||||
|
|
||||||
use error::{FromHttpRequestError, FromHttpResponseError, IntoHttpError};
|
use error::{FromHttpRequestError, FromHttpResponseError, IntoHttpError};
|
||||||
|
|
||||||
/// Gives users the ability to define their own serializable / deserializable errors.
|
|
||||||
pub trait EndpointError: StdError + Sized + 'static {
|
|
||||||
/// Tries to construct `Self` from an `http::Response`.
|
|
||||||
///
|
|
||||||
/// This will always return `Err` variant when no `error` field is defined in
|
|
||||||
/// the `ruma_api` macro.
|
|
||||||
fn try_from_response<T: Buf>(
|
|
||||||
response: http::Response<T>,
|
|
||||||
) -> Result<Self, error::ResponseDeserializationError>;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A request type for a Matrix API endpoint, used for sending requests.
|
/// A request type for a Matrix API endpoint, used for sending requests.
|
||||||
pub trait OutgoingRequest: Sized {
|
pub trait OutgoingRequest: Sized {
|
||||||
/// A type capturing the expected error conditions the server can return.
|
/// A type capturing the expected error conditions the server can return.
|
||||||
@ -324,6 +313,17 @@ pub trait OutgoingResponse {
|
|||||||
fn try_into_http_response(self) -> Result<http::Response<Vec<u8>>, IntoHttpError>;
|
fn try_into_http_response(self) -> Result<http::Response<Vec<u8>>, IntoHttpError>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Gives users the ability to define their own serializable / deserializable errors.
|
||||||
|
pub trait EndpointError: OutgoingResponse + StdError + Sized + 'static {
|
||||||
|
/// Tries to construct `Self` from an `http::Response`.
|
||||||
|
///
|
||||||
|
/// This will always return `Err` variant when no `error` field is defined in
|
||||||
|
/// the `ruma_api` macro.
|
||||||
|
fn try_from_http_response<T: Buf>(
|
||||||
|
response: http::Response<T>,
|
||||||
|
) -> Result<Self, error::ResponseDeserializationError>;
|
||||||
|
}
|
||||||
|
|
||||||
/// Marker trait for requests that don't require authentication, for the client side.
|
/// Marker trait for requests that don't require authentication, for the client side.
|
||||||
pub trait OutgoingNonAuthRequest: OutgoingRequest {}
|
pub trait OutgoingNonAuthRequest: OutgoingRequest {}
|
||||||
|
|
||||||
|
@ -107,7 +107,7 @@ impl IncomingResponse for Response {
|
|||||||
Ok(Response)
|
Ok(Response)
|
||||||
} else {
|
} else {
|
||||||
Err(FromHttpResponseError::Http(ServerError::Known(
|
Err(FromHttpResponseError::Http(ServerError::Known(
|
||||||
<Void as EndpointError>::try_from_response(http_response)?,
|
<Void as EndpointError>::try_from_http_response(http_response)?,
|
||||||
)))
|
)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,10 @@
|
|||||||
use std::{collections::BTreeMap, fmt, time::Duration};
|
use std::{collections::BTreeMap, fmt, time::Duration};
|
||||||
|
|
||||||
use bytes::Buf;
|
use bytes::Buf;
|
||||||
use ruma_api::{error::ResponseDeserializationError, EndpointError};
|
use ruma_api::{
|
||||||
|
error::{IntoHttpError, ResponseDeserializationError},
|
||||||
|
EndpointError, OutgoingResponse,
|
||||||
|
};
|
||||||
use ruma_identifiers::RoomVersionId;
|
use ruma_identifiers::RoomVersionId;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use serde_json::{from_reader as from_json_reader, to_vec as to_json_vec, Value as JsonValue};
|
use serde_json::{from_reader as from_json_reader, to_vec as to_json_vec, Value as JsonValue};
|
||||||
@ -203,7 +206,7 @@ pub struct Error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl EndpointError for Error {
|
impl EndpointError for Error {
|
||||||
fn try_from_response<T: Buf>(
|
fn try_from_http_response<T: Buf>(
|
||||||
response: http::Response<T>,
|
response: http::Response<T>,
|
||||||
) -> Result<Self, ResponseDeserializationError> {
|
) -> Result<Self, ResponseDeserializationError> {
|
||||||
let status = response.status();
|
let status = response.status();
|
||||||
@ -233,13 +236,13 @@ impl ErrorBody {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Error> for http::Response<Vec<u8>> {
|
impl OutgoingResponse for Error {
|
||||||
fn from(error: Error) -> http::Response<Vec<u8>> {
|
fn try_into_http_response(self) -> Result<http::Response<Vec<u8>>, IntoHttpError> {
|
||||||
http::Response::builder()
|
http::Response::builder()
|
||||||
.header(http::header::CONTENT_TYPE, "application/json")
|
.header(http::header::CONTENT_TYPE, "application/json")
|
||||||
.status(error.status_code)
|
.status(self.status_code)
|
||||||
.body(to_json_vec(&ErrorBody::from(error)).unwrap())
|
.body(to_json_vec(&ErrorBody::from(self))?)
|
||||||
.unwrap()
|
.map_err(Into::into)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,7 +3,10 @@
|
|||||||
use std::{collections::BTreeMap, fmt};
|
use std::{collections::BTreeMap, fmt};
|
||||||
|
|
||||||
use bytes::Buf;
|
use bytes::Buf;
|
||||||
use ruma_api::{error::ResponseDeserializationError, EndpointError};
|
use ruma_api::{
|
||||||
|
error::{IntoHttpError, ResponseDeserializationError},
|
||||||
|
EndpointError, OutgoingResponse,
|
||||||
|
};
|
||||||
use ruma_serde::Outgoing;
|
use ruma_serde::Outgoing;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use serde_json::{
|
use serde_json::{
|
||||||
@ -134,28 +137,28 @@ impl From<MatrixError> for UiaaResponse {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl EndpointError for UiaaResponse {
|
impl EndpointError for UiaaResponse {
|
||||||
fn try_from_response<T: Buf>(
|
fn try_from_http_response<T: Buf>(
|
||||||
response: http::Response<T>,
|
response: http::Response<T>,
|
||||||
) -> Result<Self, ResponseDeserializationError> {
|
) -> Result<Self, ResponseDeserializationError> {
|
||||||
if response.status() == http::StatusCode::UNAUTHORIZED {
|
if response.status() == http::StatusCode::UNAUTHORIZED {
|
||||||
Ok(UiaaResponse::AuthResponse(from_json_reader(response.into_body().reader())?))
|
Ok(UiaaResponse::AuthResponse(from_json_reader(response.into_body().reader())?))
|
||||||
} else {
|
} else {
|
||||||
MatrixError::try_from_response(response).map(From::from)
|
MatrixError::try_from_http_response(response).map(From::from)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::error::Error for UiaaResponse {}
|
impl std::error::Error for UiaaResponse {}
|
||||||
|
|
||||||
impl From<UiaaResponse> for http::Response<Vec<u8>> {
|
impl OutgoingResponse for UiaaResponse {
|
||||||
fn from(uiaa_response: UiaaResponse) -> http::Response<Vec<u8>> {
|
fn try_into_http_response(self) -> Result<http::Response<Vec<u8>>, IntoHttpError> {
|
||||||
match uiaa_response {
|
match self {
|
||||||
UiaaResponse::AuthResponse(authentication_info) => http::Response::builder()
|
UiaaResponse::AuthResponse(authentication_info) => http::Response::builder()
|
||||||
.header(http::header::CONTENT_TYPE, "application/json")
|
.header(http::header::CONTENT_TYPE, "application/json")
|
||||||
.status(&http::StatusCode::UNAUTHORIZED)
|
.status(&http::StatusCode::UNAUTHORIZED)
|
||||||
.body(to_json_vec(&authentication_info).unwrap())
|
.body(to_json_vec(&authentication_info)?)
|
||||||
.unwrap(),
|
.map_err(Into::into),
|
||||||
UiaaResponse::MatrixError(error) => http::Response::from(error),
|
UiaaResponse::MatrixError(error) => error.try_into_http_response(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -164,7 +167,7 @@ impl From<UiaaResponse> for http::Response<Vec<u8>> {
|
|||||||
mod tests {
|
mod tests {
|
||||||
use maplit::btreemap;
|
use maplit::btreemap;
|
||||||
use matches::assert_matches;
|
use matches::assert_matches;
|
||||||
use ruma_api::EndpointError;
|
use ruma_api::{EndpointError, OutgoingResponse};
|
||||||
use serde_json::{
|
use serde_json::{
|
||||||
from_slice as from_json_slice, from_str as from_json_str, from_value as from_json_value,
|
from_slice as from_json_slice, from_str as from_json_str, from_value as from_json_value,
|
||||||
json, to_value as to_json_value, value::to_raw_value as to_raw_json_value,
|
json, to_value as to_json_value, value::to_raw_value as to_raw_json_value,
|
||||||
@ -334,7 +337,7 @@ mod tests {
|
|||||||
session: None,
|
session: None,
|
||||||
auth_error: None,
|
auth_error: None,
|
||||||
};
|
};
|
||||||
let uiaa_response: http::Response<Vec<u8>> = UiaaResponse::AuthResponse(uiaa_info).into();
|
let uiaa_response = UiaaResponse::AuthResponse(uiaa_info).try_into_http_response();
|
||||||
|
|
||||||
assert_matches!(
|
assert_matches!(
|
||||||
from_json_slice::<UiaaInfo>(uiaa_response.body()).unwrap(),
|
from_json_slice::<UiaaInfo>(uiaa_response.body()).unwrap(),
|
||||||
@ -385,7 +388,7 @@ mod tests {
|
|||||||
.body(json.as_bytes())
|
.body(json.as_bytes())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let parsed_uiaa_info = match UiaaResponse::try_from_response(http_response).unwrap() {
|
let parsed_uiaa_info = match UiaaResponse::try_from_http_response(http_response).unwrap() {
|
||||||
UiaaResponse::AuthResponse(uiaa_info) => uiaa_info,
|
UiaaResponse::AuthResponse(uiaa_info) => uiaa_info,
|
||||||
_ => panic!("Expected UiaaResponse::AuthResponse"),
|
_ => panic!("Expected UiaaResponse::AuthResponse"),
|
||||||
};
|
};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user