Skip to content

Commit

Permalink
Add transform to mark required idempotency tokens client optional (#2466
Browse files Browse the repository at this point in the history
)

Add transform to make required `@idempotencyToken` members `@clientOptional` so that they can be left empty and injected.



---------

Co-authored-by: Kevin Stich <kevin@kstich.com>
Co-authored-by: Michael Dowling <michael@mtdowling.com>
  • Loading branch information
3 people authored Nov 15, 2024
1 parent bf32a87 commit 06750df
Show file tree
Hide file tree
Showing 8 changed files with 157 additions and 0 deletions.
25 changes: 25 additions & 0 deletions docs/source-2.0/guides/smithy-build-json.rst
Original file line number Diff line number Diff line change
Expand Up @@ -573,6 +573,31 @@ applied.
use an :ref:`enum shape <enum>` instead to avoid needing to use this
transform.

.. _makeIdempotencyTokensClientOptional:

makeIdempotencyTokensClientOptional
-----------------------------------

Makes required :ref:`@idempotencyToken <idempotencyToken-trait>` members :ref:`@clientOptional <clientOptional-trait>`.

Idempotency tokens that are required should fail validation, but shouldn't be required to create a type.
This allows a default value to get injected when missing.

.. code-block:: json
{
"version": "1.0",
"projections": {
"exampleProjection": {
"transforms": [
{
"name": "makeIdempotencyTokensClientOptional"
}
]
}
}
}
.. _changeTypes:

changeTypes
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/*
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/

package software.amazon.smithy.build.transforms;

import software.amazon.smithy.build.ProjectionTransformer;
import software.amazon.smithy.build.TransformContext;
import software.amazon.smithy.model.Model;

/**
* {@code makeIdempotencyTokensClientOptional} makes {@code @idempotencyToken} fields {@code @clientOptional}.
*/
public final class MakeIdempotencyTokensClientOptional implements ProjectionTransformer {

@Override
public String getName() {
return "makeIdempotencyTokensClientOptional";
}

@Override
public Model transform(TransformContext context) {
Model model = context.getModel();
return context.getTransformer().makeIdempotencyTokensClientOptional(model);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ software.amazon.smithy.build.transforms.IncludeShapesByTag
software.amazon.smithy.build.transforms.IncludeTags
software.amazon.smithy.build.transforms.IncludeTraits
software.amazon.smithy.build.transforms.IncludeTraitsByTag
software.amazon.smithy.build.transforms.MakeIdempotencyTokensClientOptional
software.amazon.smithy.build.transforms.RemoveDeprecatedShapes
software.amazon.smithy.build.transforms.RemoveTraitDefinitions
software.amazon.smithy.build.transforms.RemoveUnusedShapes
software.amazon.smithy.build.transforms.RenameShapes
Original file line number Diff line number Diff line change
Expand Up @@ -315,6 +315,18 @@ public void removeShapesDeprecatedBeforeVersion(String relativeVersion) {
});
}

/**
* Makes {@code idempotencyToken} fields {@code clientOptional}.
*
* @see ModelTransformer#makeIdempotencyTokensClientOptional(Model)
*/
public void makeIdempotencyTokensClientOptional() {
transforms.add((model, transformer) -> {
LOGGER.finest("Making `@idempotencyToken` fields `@clientOptional`");
return transformer.makeIdempotencyTokensClientOptional(model);
});
}

/**
* Changes each compatible string shape with the enum trait to an enum shape.
*
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/

package software.amazon.smithy.model.transform;

import software.amazon.smithy.model.Model;
import software.amazon.smithy.model.shapes.Shape;
import software.amazon.smithy.model.traits.ClientOptionalTrait;
import software.amazon.smithy.model.traits.IdempotencyTokenTrait;
import software.amazon.smithy.model.traits.RequiredTrait;

/**
* Makes {@code idempotencyToken} members {@code clientOptional}, so they can be injected if missing.
*/
final class MakeIdempotencyTokenClientOptional {
private MakeIdempotencyTokenClientOptional() {}

public static Model transform(Model model) {
return ModelTransformer.create().mapShapes(model, shape -> {
if (shape.isMemberShape()
&& shape.hasTrait(RequiredTrait.class)
&& shape.hasTrait(IdempotencyTokenTrait.class)
&& !shape.hasTrait(ClientOptionalTrait.class)) {
return Shape.shapeToBuilder(shape).addTrait(new ClientOptionalTrait()).build();
}
return shape;
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -720,4 +720,17 @@ public Model filterDeprecatedRelativeDate(Model model, String relativeDate) {
public Model filterDeprecatedRelativeVersion(Model model, String relativeVersion) {
return new FilterDeprecatedRelativeVersion(relativeVersion).transform(this, model);
}

/**
* Makes any {@code @idempotencyToken} fields {@code @clientOptional} so that missing tokens can be injected.
*
* <p>Idempotency tokens that are required should fail validation, but shouldn't be required to create a type,
* allowing for a default value to be injected when missing.
*
* @param model Model to transform.
* @return Returns the transformed model.
*/
public Model makeIdempotencyTokensClientOptional(Model model) {
return MakeIdempotencyTokenClientOptional.transform(model);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/

package software.amazon.smithy.model.transform;

import static org.junit.jupiter.api.Assertions.assertTrue;

import org.junit.jupiter.api.Test;
import software.amazon.smithy.model.Model;
import software.amazon.smithy.model.shapes.Shape;
import software.amazon.smithy.model.shapes.ShapeId;
import software.amazon.smithy.model.traits.ClientOptionalTrait;
import software.amazon.smithy.model.traits.IdempotencyTokenTrait;
import software.amazon.smithy.model.traits.RequiredTrait;

public class MakeIdempotencyTokenClientOptionalTest {
private static final ShapeId operationInput = ShapeId.from("smithy.example#IdempotencyTokenRequiredInput");

@Test
void compareTransform() {
Model before = Model.assembler()
.addImport(FlattenPaginationInfoTest.class.getResource("idempotency-token.smithy"))
.assemble()
.unwrap();
Model result = ModelTransformer.create().makeIdempotencyTokensClientOptional(before);

Shape input = result.expectShape(operationInput);
Shape member = result.expectShape(input.getMember("token").get().getId());

assertTrue(member.hasTrait(ClientOptionalTrait.class));
assertTrue(member.hasTrait(RequiredTrait.class));
assertTrue(member.hasTrait(IdempotencyTokenTrait.class));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
$version: "2.0"

namespace smithy.example

operation IdempotencyTokenRequired {
input := {
@idempotencyToken
@required
token: String
}
}

0 comments on commit 06750df

Please sign in to comment.