Skip to content

Commit c8684a4

Browse files
committed
client-api: Return 201 from update_device when a device is created.
The PUT /devices/{deviceId} response carries a `created` flag mapping to 201 on creation and 200 on update, hand-written because the response macro fixes the status (MSC4190). Signed-off-by: Jason Volk <jason@zemos.net>
1 parent c9f810c commit c8684a4

1 file changed

Lines changed: 60 additions & 6 deletions

File tree

crates/ruma-client-api/src/device/update_device.rs

Lines changed: 60 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ pub mod v3 {
1111
1212
use ruma_common::{
1313
OwnedDeviceId,
14-
api::{auth_scheme::AccessToken, request, response},
14+
api::{auth_scheme::AccessToken, request},
1515
metadata,
1616
};
1717

@@ -42,9 +42,18 @@ pub mod v3 {
4242
}
4343

4444
/// Response type for the `update_device` endpoint.
45-
#[response]
46-
#[derive(Default)]
47-
pub struct Response {}
45+
///
46+
/// The HTTP status reflects whether a device was created or merely updated:
47+
/// an application service creating a device receives `201 Created`, any
48+
/// other update receives `200 OK` (MSC4190). The body is empty in both
49+
/// cases, so this is hand-written rather than generated by the `response`
50+
/// macro, whose status is fixed.
51+
#[derive(Clone, Debug, Default)]
52+
#[cfg_attr(not(ruma_unstable_exhaustive_types), non_exhaustive)]
53+
pub struct Response {
54+
/// Whether a new device was created rather than an existing one updated.
55+
pub created: bool,
56+
}
4857

4958
impl Request {
5059
/// Creates a new `Request` with the given device ID.
@@ -54,9 +63,54 @@ pub mod v3 {
5463
}
5564

5665
impl Response {
57-
/// Creates an empty `Response`.
66+
/// Creates a `Response` for an updated device (`200 OK`).
5867
pub fn new() -> Self {
59-
Self {}
68+
Self { created: false }
69+
}
70+
71+
/// Creates a `Response` for a newly created device (`201 Created`).
72+
pub fn created() -> Self {
73+
Self { created: true }
74+
}
75+
}
76+
77+
#[cfg(feature = "server")]
78+
impl ruma_common::api::OutgoingResponse for Response {
79+
fn try_into_http_response<T: Default + bytes::BufMut>(
80+
self,
81+
) -> Result<http::Response<T>, ruma_common::api::error::IntoHttpError> {
82+
let status =
83+
if self.created { http::StatusCode::CREATED } else { http::StatusCode::OK };
84+
85+
let mut response = http::Response::builder()
86+
.status(status)
87+
.body(ruma_common::serde::slice_to_buf(b"{}"))?;
88+
89+
response
90+
.headers_mut()
91+
.insert(http::header::CONTENT_TYPE, ruma_common::http_headers::APPLICATION_JSON);
92+
93+
Ok(response)
94+
}
95+
}
96+
97+
#[cfg(feature = "client")]
98+
impl ruma_common::api::IncomingResponse for Response {
99+
type EndpointError = ruma_common::api::error::Error;
100+
101+
fn try_from_http_response<T: AsRef<[u8]>>(
102+
response: http::Response<T>,
103+
) -> Result<Self, ruma_common::api::error::FromHttpResponseError<Self::EndpointError>>
104+
{
105+
if response.status().as_u16() >= 400 {
106+
return Err(ruma_common::api::error::FromHttpResponseError::Server(
107+
<Self::EndpointError as ruma_common::api::EndpointError>::from_http_response(
108+
response,
109+
),
110+
));
111+
}
112+
113+
Ok(Self { created: response.status() == http::StatusCode::CREATED })
60114
}
61115
}
62116
}

0 commit comments

Comments
 (0)