api: Introduce OutgoingResponse trait

This commit is contained in:
Jonas Platte 2021-04-10 15:57:07 +02:00
parent 6f5c1ee953
commit b122dcc135
No known key found for this signature in database
GPG Key ID: CC154DE0E30B7C67
6 changed files with 34 additions and 32 deletions

View File

@ -116,7 +116,7 @@ impl Response {
if segments.last().unwrap().ident == "Option" =>
{
quote! {
if let Some(header) = response.#field_name {
if let Some(header) = self.#field_name {
headers
.insert(
#http::header::#header_name,
@ -129,7 +129,7 @@ impl Response {
headers
.insert(
#http::header::#header_name,
response.#field_name.parse()?,
self.#field_name.parse()?,
);
},
};
@ -152,13 +152,13 @@ impl Response {
if let Some(field) = self.newtype_raw_body_field() {
let field_name = field.ident.as_ref().expect("expected field to have an identifier");
let span = field.span();
return quote_spanned!(span=> response.#field_name);
return quote_spanned!(span=> self.#field_name);
}
let body = if let Some(field) = self.newtype_body_field() {
let field_name = field.ident.as_ref().expect("expected field to have an identifier");
let span = field.span();
quote_spanned!(span=> response.#field_name)
quote_spanned!(span=> self.#field_name)
} else {
let fields = self.fields.iter().filter_map(|response_field| {
if let ResponseField::Body(ref field) = *response_field {
@ -170,7 +170,7 @@ impl Response {
Some(quote_spanned! {span=>
#( #cfg_attrs )*
#field_name: response.#field_name
#field_name: self.#field_name
})
} else {
None
@ -285,10 +285,13 @@ impl Response {
#[automatically_derived]
#[cfg(feature = "server")]
impl ::std::convert::TryFrom<Response> for #http::Response<Vec<u8>> {
type Error = #ruma_api::error::IntoHttpError;
fn try_from(response: Response) -> ::std::result::Result<Self, Self::Error> {
impl #ruma_api::OutgoingResponse for Response {
fn try_into_http_response(
self,
) -> ::std::result::Result<
#http::Response<::std::vec::Vec<u8>>,
#ruma_api::error::IntoHttpError,
> {
let mut resp_builder = #http::Response::builder()
.header(#http::header::CONTENT_TYPE, "application/json");
@ -300,8 +303,7 @@ impl Response {
// This cannot fail because we parse each header value
// checking for errors as each value is inserted and
// we only allow keys from the `http::header` module.
let response = resp_builder.body(#body).unwrap();
Ok(response)
Ok(resp_builder.body(#body).unwrap())
}
}

View File

@ -20,7 +20,7 @@
#[cfg(not(all(feature = "client", feature = "server")))]
compile_error!("ruma_api's Cargo features only exist as a workaround are not meant to be disabled");
use std::{convert::TryInto, error::Error as StdError};
use std::{convert::TryInto as _, error::Error as StdError};
use bytes::Buf;
use http::Method;
@ -306,7 +306,7 @@ pub trait IncomingRequest: Sized {
type EndpointError: EndpointError;
/// Response type to return when the request is successful.
type OutgoingResponse: TryInto<http::Response<Vec<u8>>, Error = IntoHttpError>;
type OutgoingResponse: OutgoingResponse;
/// Metadata about the endpoint.
const METADATA: Metadata;
@ -315,6 +315,15 @@ pub trait IncomingRequest: Sized {
fn try_from_http_request(req: http::Request<Vec<u8>>) -> Result<Self, FromHttpRequestError>;
}
/// A request type for a Matrix API endpoint, used for sending responses.
pub trait OutgoingResponse {
/// Tries to convert this response into an `http::Response`.
///
/// This method should only fail when when invalid header values are specified. It may also
/// fail with a serialization error in case of bugs in Ruma though.
fn try_into_http_response(self) -> Result<http::Response<Vec<u8>>, IntoHttpError>;
}
/// Marker trait for requests that don't require authentication, for the client side.
pub trait OutgoingNonAuthRequest: OutgoingRequest {}

View File

@ -1,7 +1,5 @@
use std::convert::TryFrom;
use http::header::{Entry, CONTENT_TYPE};
use ruma_api::{ruma_api, OutgoingRequest as _};
use ruma_api::{ruma_api, OutgoingRequest as _, OutgoingResponse as _};
ruma_api! {
metadata: {
@ -30,7 +28,7 @@ ruma_api! {
#[test]
fn response_content_type_override() {
let res = Response { stuff: "magic".into() };
let mut http_res = http::Response::<Vec<u8>>::try_from(res).unwrap();
let mut http_res = res.try_into_http_response().unwrap();
// Test that we correctly replaced the default content type,
// not adding another content-type header.

View File

@ -7,6 +7,7 @@ use http::{header::CONTENT_TYPE, method::Method};
use ruma_api::{
error::{FromHttpRequestError, FromHttpResponseError, IntoHttpError, ServerError, Void},
AuthScheme, EndpointError, IncomingRequest, IncomingResponse, Metadata, OutgoingRequest,
OutgoingResponse,
};
use ruma_identifiers::{RoomAliasId, RoomId};
use ruma_serde::Outgoing;
@ -113,10 +114,8 @@ impl IncomingResponse for Response {
}
}
impl TryFrom<Response> for http::Response<Vec<u8>> {
type Error = IntoHttpError;
fn try_from(_: Response) -> Result<http::Response<Vec<u8>>, Self::Error> {
impl OutgoingResponse for Response {
fn try_into_http_response(self) -> Result<http::Response<Vec<u8>>, IntoHttpError> {
let response = http::Response::builder()
.header(CONTENT_TYPE, "application/json")
.body(b"{}".to_vec())

View File

@ -1,6 +1,4 @@
use std::convert::TryFrom;
use ruma_api::{ruma_api, OutgoingRequest as _};
use ruma_api::{ruma_api, OutgoingRequest as _, OutgoingResponse as _};
ruma_api! {
metadata: {
@ -27,7 +25,7 @@ fn empty_request_http_repr() {
#[test]
fn empty_response_http_repr() {
let res = Response {};
let http_res = http::Response::<Vec<u8>>::try_from(res).unwrap();
let http_res = res.try_into_http_response().unwrap();
assert_eq!(http_res.body(), b"{}");
}

View File

@ -1,9 +1,7 @@
use std::convert::TryFrom;
use bytes::Buf;
use ruma_api::{
error::{FromHttpResponseError, IntoHttpError, Void},
ruma_api, IncomingResponse,
ruma_api, IncomingResponse, OutgoingResponse,
};
use ruma_serde::Outgoing;
@ -37,10 +35,8 @@ impl IncomingResponse for Response {
}
}
impl TryFrom<Response> for http::Response<Vec<u8>> {
type Error = IntoHttpError;
fn try_from(_: Response) -> Result<Self, Self::Error> {
impl OutgoingResponse for Response {
fn try_into_http_response(self) -> Result<http::Response<Vec<u8>>, IntoHttpError> {
todo!()
}
}