18. Shape closures

A shape closure is a named set of shapes that consumers, such as code generators, can refer to by id. Closures are declared in model metadata and consumed by tools that need to operate on a discrete subset of the model without anchoring that subset to a service.

18.1. Shape closures vs. service closures

A service closure is the set of shapes connected to a service through resources, operations, and members. The membership of a service closure is implicit in the model. It is determined by traversing neighbor relationships from a service shape, and any tool that wants to operate on it just needs the service id.

A shape closure is intentionally decoupled from services. Its shapes are specified by namespace or selector and the result is identified by an id that does not correspond to any shape in the model.

This makes shape closures the right tool when a service is not needed. For example, a code generator may want to generate types without a service or client wrapper. This is also useful for modeling events that aren't part of an operation response.

18.2. shapeClosures metadata

Shape closures are declared with the shapeClosures metadata key. The value is a list of ShapeClosure structures with the following members:

Property

Type

Description

id

string

Required. The namespaced identifier of the closure (for example, com.example#EventShapes). The id is used by tools to refer to the closure. The id follows the same format as a shape id, MUST be unique across all closures in the model, and MUST NOT refer to a shape that exists in the model.

This identifier is not intended to be semantically significant. The requirement for a namespace is intended to reduce the chance for naming collisions, not to suggest the namespace that any generated artifacts must be generated into.

includeNamespaces

[string]

Namespaces whose shapes are included in the closure.

includeBySelector

string

A selector whose matched shapes are included in the closure.

rename

map of shape ID to string

Disambiguates shape name conflicts in the closure. Map keys are shape IDs contained in the closure, and map values are the disambiguated shape names to use in the context of the closure. Each given shape ID MUST reference a shape contained in the closure. Each given map value MUST match the smithy:Identifier production used for shape IDs. Renaming a shape does not give the shape a new shape ID.

  • No renamed shape name can case-insensitively match any other renamed shape name or the name of a non-renamed shape contained in the closure.

  • Member shapes MAY NOT be renamed.

  • Service, resource, and operation shapes MAY NOT be renamed. Renaming shapes is intended for incidental naming conflicts, not for renaming the fundamental concepts of an API.

  • Shapes from other namespaces marked as private MAY be renamed.

  • A rename MUST use a name that is case-sensitively different from the original shape ID name.

A closure MUST define at least one of includeNamespaces or includeBySelector.

The resolved closure is expanded transitively through directed neighbor relationships from every shape matched by includeNamespaces or includeBySelector.

18.3. Example

$version: "2"

metadata shapeClosures = [
    {
        id: "com.example#EventShapes"
        includeNamespaces: ["com.example"]
    }
]

namespace com.example

structure Event {
    message: String
}

Tools that consume a closure use its id to look up the set of shapes to operate on. For example, a code generator might generate types for every shape in the named closure, or the includeClosures build transform might filter the model down to those shapes.