Skip to content

Commit

Permalink
Add "double" format to epoch-seconds timestamps
Browse files Browse the repository at this point in the history
OpenAPI supports a format called "double" on the "number" type to indicate
that a number is a double precision floating point number. Timestamps
that use epoch-seconds have been updated to use this format so that
stricter JSON Schema validators don't error when they encounter
decimals. "double" is only added as a format when performing OpenAPI
conversions and are not added by default when performing JSON Schema
conversions.
  • Loading branch information
mtdowling committed May 17, 2021
1 parent 3712c98 commit f31cba5
Show file tree
Hide file tree
Showing 9 changed files with 38 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -382,7 +382,8 @@
"type": "object",
"properties": {
"createdAt": {
"type": "number"
"type": "number",
"format": "double"
},
"id": {
"type": "string"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -382,7 +382,8 @@
"type": "object",
"properties": {
"createdAt": {
"type": "number"
"type": "number",
"format": "double"
},
"id": {
"type": "string"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,8 @@
"type": "object",
"properties": {
"createdAt": {
"type": "number"
"type": "number",
"format": "double"
},
"id": {
"type": "string"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,8 @@
"type": "object",
"properties": {
"createdAt": {
"type": "number"
"type": "number",
"format": "double"
},
"id": {
"type": "string"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,13 @@

import java.util.HashSet;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import software.amazon.smithy.model.node.Node;
import software.amazon.smithy.model.node.NodeMapper;
import software.amazon.smithy.model.node.ObjectNode;
import software.amazon.smithy.model.shapes.Shape;
import software.amazon.smithy.model.shapes.ShapeId;
import software.amazon.smithy.model.traits.TimestampFormatTrait;

Expand Down Expand Up @@ -329,4 +331,20 @@ public ShapeId getService() {
public void setService(ShapeId service) {
this.service = service;
}

/**
* Detects the TimestampFormat of the given shape, falling back to the
* configured default format specified in {@link #setDefaultTimestampFormat(TimestampFormatTrait.Format)}.
*
* @param shape Shape to extract the timestamp format from.
* @return Returns the optionally detected format.
*/
public Optional<String> detectJsonTimestampFormat(Shape shape) {
if (shape.isTimestampShape() || shape.hasTrait(TimestampFormatTrait.class)) {
return Optional.of(shape.getTrait(TimestampFormatTrait.class)
.map(TimestampFormatTrait::getValue)
.orElseGet(() -> getDefaultTimestampFormat().toString()));
}
return Optional.empty();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ public byte getOrder() {

@Override
public Schema.Builder updateSchema(Shape shape, Schema.Builder builder, JsonSchemaConfig config) {
String format = extractTimestampFormat(shape, config);
String format = config.detectJsonTimestampFormat(shape).orElse(null);

if (format == null) {
return builder;
Expand All @@ -49,14 +49,4 @@ public Schema.Builder updateSchema(Shape shape, Schema.Builder builder, JsonSche
return format.startsWith("epoch-") ? builder.type("number") : builder.type("string");
}
}

private static String extractTimestampFormat(Shape shape, JsonSchemaConfig config) {
if (shape.isTimestampShape() || shape.hasTrait(TimestampFormatTrait.class)) {
return shape.getTrait(TimestampFormatTrait.class)
.map(TimestampFormatTrait::getValue)
.orElseGet(() -> config.getDefaultTimestampFormat().toString());
}

return null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
import software.amazon.smithy.model.traits.DeprecatedTrait;
import software.amazon.smithy.model.traits.ExternalDocumentationTrait;
import software.amazon.smithy.model.traits.SensitiveTrait;
import software.amazon.smithy.model.traits.TimestampFormatTrait;
import software.amazon.smithy.openapi.OpenApiConfig;
import software.amazon.smithy.openapi.model.ExternalDocumentation;
import software.amazon.smithy.utils.MapUtils;
Expand Down Expand Up @@ -88,6 +89,12 @@ public Schema.Builder updateSchema(Shape shape, Schema.Builder builder, JsonSche
String blobFormat = ((OpenApiConfig) config).getDefaultBlobFormat();
return builder.format(blobFormat);
}
} else if (shape.isTimestampShape()) {
// Add the "double" format when epoch-seconds is used
// to account for optional millisecond precision.
config.detectJsonTimestampFormat(shape)
.filter(format -> format.equals(TimestampFormatTrait.EPOCH_SECONDS))
.ifPresent(format -> builder.format("double"));
} else if (shape.hasTrait(SensitiveTrait.class)) {
builder.format("password");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,8 @@
"type": "string"
},
"time": {
"type": "number"
"type": "number",
"format": "double"
},
"list": {
"type": "array",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,8 @@
"type": "string"
},
"time": {
"type": "number"
"type": "number",
"format": "double"
},
"list": {
"type": "array",
Expand Down

0 comments on commit f31cba5

Please sign in to comment.