Skip to content

Commit 3ee5d06

Browse files
Make OperationExtension store the absolute shape ID (#2276)
* Do not alter Operation shape ID * Add OperationExtensionExt test * Add CHANGELOG.next.toml entry * Apply suggestions from code review Co-authored-by: Luca Palmieri <20745048+LukeMathWalker@users.noreply.github.com> --------- Co-authored-by: Luca Palmieri <20745048+LukeMathWalker@users.noreply.github.com>
1 parent 47f6bd8 commit 3ee5d06

File tree

2 files changed

+80
-7
lines changed

2 files changed

+80
-7
lines changed

CHANGELOG.next.toml

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,3 +82,45 @@ message = "Fix broken doc link for `tokio_stream::Stream` that is a re-export of
8282
references = ["smithy-rs#2271"]
8383
meta = { "breaking" = false, "tada" = false, "bug" = true }
8484
author = "ysaito1001"
85+
86+
[[smithy-rs]]
87+
message = """
88+
Fix `name` and `absolute` methods on `OperationExtension`.
89+
90+
The older, [now removed](https://github.com/awslabs/smithy-rs/pull/2161), service builder would insert `OperationExtension` into the `http::Response` containing the [absolute shape ID](https://smithy.io/2.0/spec/model.html#grammar-token-smithy-AbsoluteRootShapeId) with the `#` symbol replaced with a `.`. When [reintroduced](https://github.com/awslabs/smithy-rs/pull/2157) into the new service builder machinery the behavior was changed - we now do _not_ perform the replace. This change fixes the documentation and `name`/`absolute` methods of the `OperationExtension` API to match this new behavior.
91+
92+
In the old service builder, `OperationExtension` was initialized, by the framework, and then used as follows:
93+
94+
```rust
95+
let ext = OperationExtension::new("com.amazonaws.CompleteSnapshot");
96+
97+
// This is expected
98+
let name = ext.name(); // "CompleteSnapshot"
99+
let namespace = ext.namespace(); // = "com.amazonaws";
100+
```
101+
102+
When reintroduced, `OperationExtension` was initialized by the `Plugin` and then used as follows:
103+
104+
```rust
105+
let ext = OperationExtension::new("com.amazonaws#CompleteSnapshot");
106+
107+
// This is the bug
108+
let name = ext.name(); // "amazonaws#CompleteSnapshot"
109+
let namespace = ext.namespace(); // = "com";
110+
```
111+
112+
The intended behavior is now restored:
113+
114+
```rust
115+
let ext = OperationExtension::new("com.amazonaws#CompleteSnapshot");
116+
117+
// This is expected
118+
let name = ext.name(); // "CompleteSnapshot"
119+
let namespace = ext.namespace(); // = "com.amazonaws";
120+
```
121+
122+
The rationale behind this change is that the previous design was tailored towards a specific internal use case and shouldn't be enforced on all customers.
123+
"""
124+
references = ["smithy-rs#2276"]
125+
meta = { "breaking" = true, "tada" = false, "bug" = true, "target" = "server"}
126+
author = "hlbarber"

rust-runtime/aws-smithy-http-server/src/extension.rs

Lines changed: 38 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,7 @@ pub use crate::request::extension::{Extension, MissingExtension};
3535
/// This extension type is inserted, via the [`OperationExtensionPlugin`], whenever it has been correctly determined
3636
/// that the request should be routed to a particular operation. The operation handler might not even get invoked
3737
/// because the request fails to deserialize into the modeled operation input.
38-
///
39-
/// The format given must be the absolute shape ID with `#` replaced with a `.`.
40-
#[derive(Debug, Clone)]
38+
#[derive(Debug, Clone, PartialEq, Eq)]
4139
pub struct OperationExtension {
4240
absolute: &'static str,
4341

@@ -49,16 +47,16 @@ pub struct OperationExtension {
4947
#[derive(Debug, Clone, Error, PartialEq, Eq)]
5048
#[non_exhaustive]
5149
pub enum ParseError {
52-
#[error(". was not found - missing namespace")]
50+
#[error("# was not found - missing namespace")]
5351
MissingNamespace,
5452
}
5553

5654
#[allow(deprecated)]
5755
impl OperationExtension {
58-
/// Creates a new [`OperationExtension`] from the absolute shape ID of the operation with `#` symbol replaced with a `.`.
56+
/// Creates a new [`OperationExtension`] from the absolute shape ID.
5957
pub fn new(absolute_operation_id: &'static str) -> Result<Self, ParseError> {
6058
let (namespace, name) = absolute_operation_id
61-
.rsplit_once('.')
59+
.rsplit_once('#')
6260
.ok_or(ParseError::MissingNamespace)?;
6361
Ok(Self {
6462
absolute: absolute_operation_id,
@@ -236,11 +234,15 @@ impl Deref for RuntimeErrorExtension {
236234

237235
#[cfg(test)]
238236
mod tests {
237+
use tower::{service_fn, ServiceExt};
238+
239+
use crate::{operation::OperationShapeExt, proto::rest_json_1::RestJson1};
240+
239241
use super::*;
240242

241243
#[test]
242244
fn ext_accept() {
243-
let value = "com.amazonaws.ebs.CompleteSnapshot";
245+
let value = "com.amazonaws.ebs#CompleteSnapshot";
244246
let ext = OperationExtension::new(value).unwrap();
245247

246248
assert_eq!(ext.absolute(), value);
@@ -256,4 +258,33 @@ mod tests {
256258
ParseError::MissingNamespace
257259
)
258260
}
261+
262+
#[tokio::test]
263+
async fn plugin() {
264+
struct DummyOp;
265+
266+
impl OperationShape for DummyOp {
267+
const NAME: &'static str = "com.amazonaws.ebs#CompleteSnapshot";
268+
269+
type Input = ();
270+
type Output = ();
271+
type Error = ();
272+
}
273+
274+
// Apply `Plugin`.
275+
let operation = DummyOp::from_handler(|_| async { Ok(()) });
276+
let plugins = PluginPipeline::new().insert_operation_extension();
277+
let op = Plugin::<RestJson1, DummyOp, _, _>::map(&plugins, operation);
278+
279+
// Apply `Plugin`s `Layer`.
280+
let layer = op.layer;
281+
let svc = service_fn(|_: http::Request<()>| async { Ok::<_, ()>(http::Response::new(())) });
282+
let svc = layer.layer(svc);
283+
284+
// Check for `OperationExtension`.
285+
let response = svc.oneshot(http::Request::new(())).await.unwrap();
286+
let expected = OperationExtension::new(DummyOp::NAME).unwrap();
287+
let actual = response.extensions().get::<OperationExtension>().unwrap();
288+
assert_eq!(*actual, expected);
289+
}
259290
}

0 commit comments

Comments
 (0)