Resource traits#

nestedProperties trait#

Summary

Allows the binding of resource properties to occur within a nested structure deeper than the lifecycle operation's input or output shape, or within the element structure of a list targeted by a collection operation's input or output member.

Trait selector

operation -[input, output]-> structure > member :test(> structure, > list > member > structure)

A member of a top-level input or output structure member targeting a structure or a list of structures

Value type

Annotation trait.

Provided by

Provided by the prelude, available to all models.

By default, resource properties are resolved by looking at top-level input and output members. The @nestedProperties trait is used when the properties of a resource are nested one level deeper than top-level input and output members.

resource Forecast {
    properties: { chanceOfRain: Float }
    read: GetForecast
}

@readonly
operation GetForecast {
   output: GetForecastOutput
}

structure GetForecastOutput {
    @nestedProperties
    forecastData: ForecastData
}

structure ForecastData for Forecast {
    $chanceOfRain
}

See also

Member target elision syntax is used to define structure members for a resource property, identifier, or mixin member that do not repeat the target definition.

The shape targeted by the member marked with this trait will have its members used for resource property bindings. These members may not use property trait, or notProperty trait, and Smithy will not perform any resource property binding exclusion or bindings with mismatched property names.

notProperty trait#

Summary

Indicates that a top-level input or output shape member is not bound to a resource property. This trait can also mark another trait as a carrier for @notProperty so that if that trait is applied to a member, the member is considered implicitly marked with @notProperty.

Trait selector

:is(operation -[input, output]-> structure > member, operation -[input, output]-> structure > member > list > member > structure > member, [trait|trait])

A top-level member of an operation's input or output shape, or a trait

Value type

Annotation trait.

Provided by

Provided by the prelude, available to all models.

By default, top-level input and output members of lifecycle operations must be bound to a resource property or identifier. Members that are neither must have this trait applied, or be annotated with a different trait that has this trait applied.

Use this trait on a resource operation input or output member that explicitly has a purpose unrelated to reading or writing resource properties. Also use this trait on a custom defined Smithy trait used to annotate input or output members for purposes unrelated to resource property modeling such as an idempotency token.

resource Forecast {
    properties: { chanceOfRain: Float }
    update: UpdateForecast
}

operation UpdateForecast {
   input: UpdateForecastInput
}

structure UpdateForecastInput for Forecast {
    $chanceOfRain

    @notProperty
    dryRun: Boolean

    @idempotencyToken
    clientToken: String
}

noReplace trait#

Summary

Indicates that the put lifecycle operation of a resource can only be used to create a resource and cannot replace an existing resource.

Trait selector

resource:test(-[put]->)

A resource with a put lifecycle operation

Value type

Annotation trait.

Provided by

Provided by the prelude, available to all models.

By default, put lifecycle operations are assumed to both create and replace an existing resource. Some APIs, however, do not support this behavior and require that a resource is first deleted before it can be replaced.

For example, this is the behavior of Amazon DynamoDB's CreateTable operation. The "Table" resource identifier, "TableName", is provided by the client, making it appropriate to model in Smithy as a put lifecycle operation. However, UpdateTable is used to update a table and attempting to call CreateTable on a table that already exists will return an error.

@noReplace
resource Table {
    put: CreateTable
}

@idempotent
operation CreateTable {
    // ...
}

property trait#

Summary

Binds a top-level input or output structure member to a resource property with a different name.

Trait selector

structure > member

A top-level member of an operation's input or output shape

Value type

An object with the following properties:

Property

Type

Description

name

string

Required Name of the resource property to bind the member to.

Provided by

Provided by the prelude, available to all models.

By default, top-level input or output shape members are bound to the resource property with the same name. In situations where this isn't possible, this trait can be used to specify which property the member is bound to.

Note

This trait should only be used for existing service APIs that need to maintain backwards compatibility with input and output structures, while enabling Smithy's resource property modeling and validation.

resource Forecast {
    properties: { chanceOfRain: Float }
    read: GetForecast
}

@readonly
operation GetForecast {
   output: GetForecastOutput
}

structure GetForecastOutput {
    @property(name: "chanceOfRain")
    howLikelyToRain: Float
}

references trait#

Summary

Defines a design-time reference to Resource shapes. Resource references allow tooling to understand the relationships between resources and how to dereference the location of a resource.

Trait selector

:is(structure, string)

Any structure or string

Value type

list of Reference structures

Provided by

Provided by the prelude, available to all models.

Reference structure#

The references trait is a list of Reference structures that contain the following members:

Property

Type

Description

service

Shape ID

The absolute shape ID of the service to which the resource is bound. As with the resource property, the provided shape ID is not required to be resolvable at build time.

resource

Shape ID

Required. The absolute shape ID of the referenced resource.

The provided shape ID is not required to be part of the model; references may refer to resources in other models without directly depending on the external package in which the resource is defined. The reference will not be resolvable at build time but MAY be resolvable at runtime if the tool has loaded more than one model.

ids

map<string, string>

Defines a mapping of each resource identifier name to a structure member name that provides its value. Each key in the map MUST refer to one of the identifier names in the identifiers property of the resource, and each value in the map MUST refer to a valid structure member name that targets a string shape.

  • This property MUST be omitted if the references trait is applied to a string shape.

  • This property MAY be omitted if the identifiers of the resource can be mapped implicitly.

rel

string

Defines the semantics of the relationship. The rel property SHOULD contain a link relation as defined in RFC 5988 Section 4 (i.e., this value SHOULD contain either a standard link relation or URI).

Runtime resolution of references#

References MAY NOT be resolvable at runtime in the following circumstances:

  1. The members that make up the ids are not present in a structure at runtime (e.g., a member is not marked as required trait)

  2. The targeted resource and/or service shape is not part of the model

  3. The reference is bound to a specific service that is unknown to the tool

Implicit identifier mappings example#

The following example creates a reference to a HistoricalForecast resource (a resource that requires the "forecastId" and "historicalId" identifiers):

$version: "2"
namespace smithy.example

resource HistoricalForecast {
    identifiers: {
        forecastId: ForecastId
        historicalId: HistoricalForecastId
    }
}

@references([{resource: HistoricalForecast}])
structure HistoricalReference {
    forecastId: ForecastId
    historicalId: HistoricalForecastId
}

Notice that in the above example, the identifiers of the resource were not explicitly mapped to structure members. This is because the targeted structure contains members with names that match the names of the identifiers of the HistoricalForecast resource.

Explicit identifier mappings example#

Explicit mappings between identifier names and structure member names can be defined if needed. For example:

$version: "2"
namespace smithy.example

@references([
    {
        resource: HistoricalForecast
        ids: {
            forecastId: "customForecastId"
            historicalId: "customHistoricalId"
        }
    }
])
structure AnotherHistoricalReference {
    customForecastId: String
    customHistoricalId: String
}

Additional examples#

The following example defines several references:

@references([
    {resource: Forecast}
    {resource: ShapeName}
    {resource: Meteorologist}
    {
        resource: com.foo.baz#Object
        service: com.foo.baz#Service
        ids: {bucket: "bucketName", object: "objectKey"}
    ])
structure ForecastInformation {
    someId: SomeShapeIdentifier

    @required
    forecastId: ForecastId

    @required
    meteorologistId: MeteorologistId

    @required
    otherData: SomeOtherShape

    @required
    bucketName: BucketName

    @required
    objectKey: ObjectKey
}

References on string shapes#

A reference can be formed on a string shape for resources that have one identifier. References applied to a string shape MUST omit the "ids" property in the reference.

resource SimpleResource {
    identifiers: {
        foo: String
    }
}

@references([{resource: SimpleResource}])
string SimpleResourceReference

Implicit ids#

The "ids" property of a reference MAY be omitted in any of the following conditions:

  1. The shape that the references trait is applied to is a string shape.

  2. The shape that the references trait is applied to is a structure shape and all of the identifier names of the resource have corresponding member names that target string shapes.

resourceIdentifier trait#

Summary

Indicates that the targeted structure member provides an identifier for a resource.

Trait selector

structure > :test(member[trait|required] > string)

Any required member of a structure that targets a string

Value type

string

Provided by

Provided by the prelude, available to all models.

The resourceIdentifier trait may only be used on members of structures for operations bound to resources. The string value provided must correspond to the name of an identifier for said resource. The trait is not required when the name of the structure member is an exact match for the name of the resource identifier.

resource File {
    identifiers: {
        directory: "String"
        fileName: "String"
    }
    read: GetFile
}

@readonly
operation GetFile {
    input: GetFileInput
    output: GetFileOutput
    errors: [NoSuchResource]
}

@input
structure GetFileInput for File {
    @required
    $directory

    // resourceIdentifier is used because the input member name
    // does not match the resource identifier name
    @resourceIdentifier("fileName")
    @required
    name: String
}

Resource lifecycle association traits#

The createsResources, putsResources, readsResources, updatesResources, and deletesResources traits declare which resources an operation affects when that relationship is not expressed through a resource's standard lifecycle operations. They let tooling understand, from the model alone, that an operation creates, replaces, reads, updates, or deletes one or more resources, and where to find the affected resources' identifiers and properties.

These traits are useful for operations that a 1:1 resource lifecycle cannot express, such as batch operations, operations that affect several resource types at once, or operations that are not bound to the resource they affect.

For an operation that is bound to a resource's standard lifecycle, including a list or other collection operation, resource properties and identifiers are bound through the operation's members, and the nestedProperties trait is used to bind them within a list element. These traits are for the operations that fall outside that standard lifecycle binding, and they locate identifiers and properties explicitly with JMESPath rather than by member binding.

Each trait is a list of bindings. A binding names a resource and, optionally, declares where the resource's identifiers and properties are located in the operation's input or output.

Identifiers, properties, and sides#

A binding can locate two independent kinds of information about the resource:

  • identifiers: where the affected resource's identifiers are located.

  • properties: where the affected resource's properties are located.

Identifiers and properties each resolve against a fixed side of the operation, determined by the trait:

Trait

Identifiers side

Properties side

createsResources

output

input

putsResources

input

input

readsResources

input

output

updatesResources

input

input

deletesResources

input

(none)

The sides reflect where the data lives: a created resource's identifier is generated into the output while its properties are supplied in the input; a read resource is selected by an identifier in the input and its state is returned in the output; and so on. deletesResources does not locate properties, because a resource is deleted by its identifier alone.

Specifying identifiers and properties#

Identifiers and properties are each optional and are specified in one of three ways:

  • Explicit: an identifiers or properties map associates each resource identifier or property name with a JMESPath expression that locates its value on the appropriate side.

  • Inferred: an identifiersFrom or propertiesFrom expression points at a nested structure or a projection whose members are matched by name to the resource's identifiers or properties. Member-name differences are reconciled with the property trait and resourceIdentifier trait, and the notProperty trait excludes a member.

  • Unspecified: neither the explicit map nor the ...From pointer is set. The binding only asserts that the operation affects the resource; nothing is inferred and nothing is validated for it. For example, @createsResources([{resource: Forecast}]) states only that the operation creates a Forecast.

The explicit map and the ...From pointer may be combined; the map overrides inference for a given name. The value located for an identifier must match the resource identifier's target shape, and the value located for a property must match the resource property's target shape.

Supported JMESPath#

Locators and ...From pointers use a structural subset of JMESPath: field access, subexpressions, wildcard projections ([*]), flatten ([]), and the current node. Functions, filters, comparators, index and slice expressions, and multi-select expressions are not supported. A ...From pointer must resolve to a nested structure or a projection of structures. It must not resolve to the whole input or output root, nor to a list, map, or scalar.

Binding structures#

createsResources, putsResources, readsResources, and updatesResources use the ResourceLifecycleBinding structure, which has the following members:

Property

Type

Description

resource

Shape ID

Required. The absolute shape ID of the affected resource. Must target a Resource shape.

identifiers

map<string, ResourceMemberBinding>

Explicit map of resource identifier name to a locator for its value.

identifiersFrom

string

Structural JMESPath pointing at a nested structure or projection from whose members identifiers are inferred by name.

properties

map<string, ResourceMemberBinding>

Explicit map of resource property name to a locator for its value.

propertiesFrom

string

Structural JMESPath pointing at a nested structure or projection from whose members properties are inferred by name.

deletesResources uses the ResourceDeletionBinding structure, which is identical but omits the properties and propertiesFrom members.

Both structures locate values with the ResourceMemberBinding structure, which has the following members:

Property

Type

Description

path

string

Required. A structural JMESPath expression that locates the value in the operation input or output.

createsResources trait#

Summary

Declares which resources an operation creates. Identifiers are located in the output; properties are located in the input.

Trait selector

operation

Value type

list of ResourceLifecycleBinding structures.

Provided by

Provided by the prelude, available to all models.

Removing a binding or changing a binding's resource is a breaking change.

@createsResources([
    {
        resource: Table
        identifiersFrom: "table"
    }
])
operation RestoreTable {
    input: RestoreTableInput
    output: RestoreTableOutput
}

@output
structure RestoreTableOutput {
    table: TableRef
}

structure TableRef for Table {
    $tableName
}

putsResources trait#

Summary

Declares which resources an operation creates or replaces with put semantics (a caller-provided identifier). Identifiers and properties are both located in the input.

Trait selector

operation

Value type

list of ResourceLifecycleBinding structures.

Provided by

Provided by the prelude, available to all models.

Removing a binding or changing a binding's resource is a breaking change.

@putsResources([
    {
        resource: Forecast
        identifiers: { forecastId: { path: "forecastId" } }
        properties: { chanceOfRain: { path: "chanceOfRain" } }
    }
])
@idempotent
operation PutForecast {
    input: PutForecastInput
    output: PutForecastOutput
}

@input
structure PutForecastInput {
    @required
    forecastId: String

    chanceOfRain: Float
}

readsResources trait#

Summary

Declares which resources an operation reads. Identifiers are located in the input; properties are located in the output.

Trait selector

operation

Value type

list of ResourceLifecycleBinding structures.

Provided by

Provided by the prelude, available to all models.

Removing a binding or changing a binding's resource is flagged as a possible breaking change.

@readsResources([
    {
        resource: Forecast
        identifiers: { forecastId: { path: "forecastId" } }
        properties: { chanceOfRain: { path: "chanceOfRain" } }
    }
])
@readonly
operation GetForecast {
    input: GetForecastInput
    output: GetForecastOutput
}

@input
structure GetForecastInput {
    @required
    forecastId: String
}

structure GetForecastOutput {
    chanceOfRain: Float
}

updatesResources trait#

Summary

Declares which resources an operation updates. Identifiers and properties are both located in the input.

Trait selector

operation

Value type

list of ResourceLifecycleBinding structures.

Provided by

Provided by the prelude, available to all models.

Removing a binding or changing a binding's resource is flagged as a possible breaking change.

@updatesResources([
    {
        resource: Forecast
        identifiers: { forecastId: { path: "forecastId" } }
        properties: { chanceOfRain: { path: "chanceOfRain" } }
    }
])
operation UpdateForecast {
    input: UpdateForecastInput
    output: UpdateForecastOutput
}

@input
structure UpdateForecastInput {
    @required
    forecastId: String

    chanceOfRain: Float
}

deletesResources trait#

Summary

Declares which resources an operation deletes. Identifiers are located in the input. Delete does not locate properties.

Trait selector

operation

Value type

list of ResourceDeletionBinding structures.

Provided by

Provided by the prelude, available to all models.

Removing a binding or changing a binding's resource is a breaking change.

@deletesResources([
    {
        resource: Table
        identifiers: { tableName: { path: "tableNames[*]" } }
    }
])
@idempotent
operation BatchDeleteTables {
    input: BatchDeleteTablesInput
    output: BatchDeleteTablesOutput
}