Skip to content

Commit

Permalink
Add transform to mark required idempotency tokens client optional
Browse files Browse the repository at this point in the history
  • Loading branch information
hpmellema committed Nov 15, 2024
1 parent bf32a87 commit bc2be87
Show file tree
Hide file tree
Showing 8 changed files with 147 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.

.. _markIdempotencyTokensClientOptional:

markIdempotencyTokensClientOptional
-----------------------------------

Marks required Idempotency token members as ``@clientOptional``.

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

.. code-block:: json
{
"version": "1.0",
"projections": {
"exampleProjection": {
"transforms": [
{
"name": "markIdempotencyTokensClientOptional"
}
]
}
}
}
.. _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 markIdempotencyTokensClientOptional} marks required idempotency token fields clientOptional.
*/
public final class MarkIdempotencyTokensClientOptional implements ProjectionTransformer {

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

@Override
public Model transform(TransformContext context) {
Model model = context.getModel();
return context.getTransformer().markIdempotencyTokensClientOptional(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.MarkIdempotencyTokensClientOptional
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) {
});
}

/**
* Marks idempotency token fields {@code clientOptional}.
*
* @see ModelTransformer#markIdempotencyTokensClientOptional(Model)
*/
public void markIdempotencyTokensClientOptional() {
transforms.add((model, transformer) -> {
LOGGER.finest("Marking Idempotency Token fields `@clientOptional`");
return transformer.filterDeprecatedRelativeVersion(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,25 @@
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;

/**
* Mark Idempotency token members as clientOptional so they can be injected if missing.
*/
final class 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 @@ -43,6 +43,7 @@
import software.amazon.smithy.model.traits.synthetic.OriginalShapeIdTrait;
import software.amazon.smithy.utils.FunctionalUtils;
import software.amazon.smithy.utils.ListUtils;
import sun.awt.ModalityListener;

/**
* Class used to transform {@link Model}s.
Expand Down Expand Up @@ -720,4 +721,17 @@ public Model filterDeprecatedRelativeDate(Model model, String relativeDate) {
public Model filterDeprecatedRelativeVersion(Model model, String relativeVersion) {
return new FilterDeprecatedRelativeVersion(relativeVersion).transform(this, model);
}

/**
* Marks any Idempotency token 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 get injected when missing.
*
* @param model Model to transform.
* @return Returns the transformed model.
*/
public Model markIdempotencyTokensClientOptional(Model model) {
return MakeIdempotencyTokenClientOptional.transform(model);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
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().markIdempotencyTokensClientOptional(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 bc2be87

Please sign in to comment.