

# Modeling resource types to use with CloudFormation
<a name="resource-type-model"></a>

The first step in creating a resource type is *modeling* that resource, which involves crafting a schema that defines the resource, its properties, and their attributes. When you initially create your resource type project using the CloudFormation CLI `init` command, one of the files created is an example resource schema. Use this schema file as a starting point for defining the shape and semantics of your resource type.

**Note**  
When naming your extension, we recommend that you don't use the following namespaces: `aws`, `amzn`, `alexa`, `amazon`, `awsquickstart`. CloudFormation doesn't block private registration using `cfn submit` for types whose names include these namespaces, but you won't be able to publish these types.

In order to be considered valid, your resource type's schema must adhere to the [Resource type definition schema](https://github.com/aws-cloudformation/aws-cloudformation-rpdk/blob/master/src/rpdk/core/data/schema/provider.definition.schema.v1.json). This meta-schema provides a means of validating your resource specification during resource development.

The Resource Type Definition Schema is a *meta-schema* that extends [draft-07](https://json-schema.org/draft-07) of the [JSON Schema](https://json-schema.org/). To simplify authoring resource specifications, the Resource Type Definition Schema constrains the scope of the full JSON Schema standard in terms of how certain validations can be expressed, and encourages consistent modeling for all resource schemas. (For full details on how the Resource Type Definition Schema differs from the full JSON schema, see [Divergence From JSON Schema](https://github.com/aws-cloudformation/cloudformation-resource-schema/blob/master/README.md#divergence-from-json-schema).)

Once you have defined your resource schema, you can use the CloudFormation CLI ` validate` command to verify that the resource schema is valid.

In terms of testing, the resource schema also determines:
+ What unit test stubs are generated in your resource package, and what contract tests are appropriate to run for the resource. When you run the CloudFormation CLI ` generate` command, the CloudFormation CLI generates empty unit tests based on the properties of the resource and their attributes.
+ Which contract tests are appropriate for CloudFormation CLI to run for your resources. When you run the ` test` command, the CloudFormation CLI runs the appropriate contract tests, based on which handlers are included in your resource schema.

**Note**  
Make sure your Lambda runtimes are up-to-date to avoid using a deprecated version. For more information, see [Updating Lambda runtimes for resource types and hooks](runtime-update.md).

## Defining property attributes
<a name="resource-type-model-setting-properties"></a>

Certain properties of a resource may have special meaning when used in different contexts. For example, a given resource property may be read-only when read back for state changes, but can be specified when used as the target of a \$1ref from a related resource. Because of this semantic difference in how this property metadata should be interpreted, certain property attributes are defined at the resource level, rather than at a property level.

These attributes include:
+ `primaryIdentifier`
+ `additionalIdentifiers`
+ `createOnlyProperties`
+ `readOnlyProperties`
+ `writeOnlyProperties`

For reference information on resource schema elements, see [Resource type schema](resource-type-schema.md).

## How to define a minimal resource
<a name="resource-type-howto-minimal"></a>

The example below displays a minimal resource type definition. In this case, the resource consists of a single optional property, `Name`, which is also specified as its primary (and only) identifier.

Note that this resource schema would require a `handlers` section with the create, read, and update handlers specified in order for the resource to actually be provisioned within a CloudFormation account.

```
{
    "typeName": "myORG::myService::myResource",
    "properties": {
        "Name": {
            "description": "The name of the resource.",
            "type": "string",
            "pattern": "^[a-zA-Z0-9_-]{0,64}$",
            "maxLength": 64
        }
    },
    "createOnlyProperties": [
        "/properties/Name"
    ],
    "identifiers": [
        [
            "/properties/Name"
        ]
    ],
    "additionalProperties": false
}
```

## Defining the account-level configuration of an extension
<a name="resource-type-howto-configuration"></a>

There might be cases where your extension includes properties that the user must specify for all instances of the extension in a given account and Region. In such cases, you can define those properties in a *configuration definition* that the user then sets at the Region level. For example, if your extension needs to access a third-party web service, you can include a configuration for the user to specify their credentials for that service.

When the user sets the configuration, CloudFormation validates it against the configuration definition, and then saves this information at the Region level. From then on, CloudFormation can access that configuration during operations involving any instances of that extension in the Region. Configurations are available to CloudFormation during all resource operations, including `read` and `list` events that don't explicitly involve a stack template.

**Note**  
Configuration definitions aren't compatible with [module](modules.md) extensions.

Your configuration definition must validate against the [provider configuration definition meta-schema](https://github.com/aws-cloudformation/cloudformation-cli/blob/master/src/rpdk/core/data/schema/provider.configuration.definition.schema.v1.json).

The `CloudFormation` property name is reserved, and can't be used to define any properties in your configuration definition.

Use the `typeConfiguration` element of the [provider definition meta-schema](https://github.com/aws-cloudformation/cloudformation-cli/blob/master/src/rpdk/core/data/schema/provider.definition.schema.v1.json) to include the configuration definition as part of your extension's schema.

**Important**  
It's strongly recommended that you use dynamic references to restrict sensitive configuration definitions, such as third-party credentials, as in the example below. For more details on dynamic references, see [Using dynamic references to specify template values](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/dynamic-references.html) in the *AWS CloudFormation User Guide*.

### Example: Defining a configuration definition to specify third-party credentials
<a name="resource-type-howto-configuration-example"></a>

The following example illustrates how you might model third-party credentials in an extension. The schema below for the `MyOrg::MyService::Resource` resource type includes a `typeConfiguration` section. The configuration definition includes a required property, `ServiceCredentials`, of type `Credentials`. As defined in the `definitions` section, the `Credentials` type includes two properties for the user to specify their credentials for a third-party service: `ApiKey` and `ApplicationKey`.

In this example, both properties must be dynamic references, as represented by the regex pattern for each property. By using dynamic references here, CloudFormation never stores the actual credential values, but instead retrieves them from AWS Secrets Manager or Systems Manager Parameter Store only when necessary. For more information about dynamic references, including how CloudFormation distinguishes which service to retrieve values from, see [Using dynamic references to specify template values](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/dynamic-references.html) in the *AWS CloudFormation User Guide*.

To see how users set configuration data for their extensions, see [Configuring extensions at the account level](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/registry-private.html#registry-set-configuration) in the *AWS CloudFormation User Guide*.

```
{
    "typeName": "MyOrg::MyService::Resource",
    "description": "Example resource type that requires third-party credentials",
    "additionalProperties": false,
    "typeConfiguration": {
        "properties": {
            "ServiceCredentials": {
                "$ref": "#/definitions/Credentials"
            }
        },
        "additionalProperties": false,
        "required": [
            "ServiceCredentials"
        ]
    },
    "definitions": {
        "Credentials": {
            "type": "object",
            "properties": {
                "ApiKey": {
                    "description": "Third-party API key",
                    "type": "string",
                    "pattern": "{{resolve:.*:[a-zA-Z0-9_.-/]+}}"
                },
                "ApplicationKey": {
                    "description": "Third-party application key",
                    "type": "string",
                    "pattern": "{{resolve:.*:[a-zA-Z0-9_.-/]+}}"
                }
            },
            "additionalProperties": false
        }
    },
    "properties": {
        "Id": {
            "type": "string"
        },
        "Name": {
            "type": "string"
        }
    },
    "primaryIdentifier": [
        "/properties/Id"
    ],
    "additionalIdentifiers": [
        ["/properties/Name"]
    ],
    "handlers": {
    }
}
```

# Resource type schema
<a name="resource-type-schema"></a>

To be considered valid, your resource type's schema must adhere to the [Resource provider definition schema](https://github.com/aws-cloudformation/aws-cloudformation-rpdk/blob/master/src/rpdk/core/data/schema/provider.definition.schema.v1.json). This meta-schema provides a means of validating your resource specification during resource development.

## Syntax
<a name="resource-type-schema-syntax"></a>

Below is the structure for a typical resource type schema. For the complete meta-schema definition, see the [Resource Provider Definition Schema](https://github.com/aws-cloudformation/cloudformation-cli/blob/master/src/rpdk/core/data/schema/provider.definition.schema.v1.json) on [GitHub](https://github.com).

```
{
    "typeName": "string",
    "description": "string",
    "sourceUrl": "string",
    "documentationUrl": "string",
    "replacementStrategy": "create_then_delete" | "delete_then_create",
    "taggable": true | false,
    "tagging": {
      "taggable": true | false,
      "tagOnCreate": true | false,
      "tagUpdatable": true | false,
      "cloudFormationSystemTags": true | false,
      "tagProperty": "json-pointer",
    },
    "definitions": {
        "definitionName": {
          . . .
        }
    },
    "properties": {
         "propertyName": {
            "description": "string",
            "type": "string",
             . . . 
            },
        },
    },
    "required": [
        "propertyName"
    ],
    "propertyTransform": {
      { 
        "/properties/propertyName": "transform"
      }  
    },
    "handlers": {
        "create": {
            "permissions": [
                "permission"
            ],
            "timeoutInMinutes": integer
        },
        "read": {
            "permissions": [
                "permission"
            ],
            "timeoutInMinutes": integer
        },
        "update": {
            "permissions": [
                "permission"
            ],
            "timeoutInMinutes": integer
        },
        "delete": {
            "permissions": [
                "permission"
            ],
            "timeoutInMinutes": integer
        },
        "list": {
            "permissions": [
                "permission"
            ],
            "timeoutInMinutes": integer
        }
    },
    "readOnlyProperties": [
        "/properties/propertyName"
    ],
    "writeOnlyProperties": [
        "/properties/propertyName"
    ],
    "conditionalCreateOnlyProperties": [
        "/properties/propertyName"
    ],
    "nonPublicProperties": [
        "/properties/propertyName"
    ],
    "nonPublicDefinitions": [
        "/properties/propertyName"
    ],
    "createOnlyProperties": [
        "/properties/propertyName"
    ],
    "deprecatedProperties": [
        "/properties/propertyName"
    ],
    "primaryIdentifier": [
        "/properties/propertyName"
    ],
    "additionalIdentifiers": [
        [ "/properties/propertyName" ]
    ],
    "typeConfiguration": {
      . . . 
    },
    "resourceLink": {
      "templateUri": "string",
      "mappings": "json-pointer"
    },
}
```

## Properties
<a name="resource-type-schema-properties"></a>

Below are the properties for a typical resource type schema.

`typeName`  <a name="schema-properties-typeName"></a>
The unique name for your resource. Specifies a three-part namespace for your resource, with a recommended pattern of `Organization::Service::Resource`.  
The following organization namespaces are reserved and can't be used in your resource type names:  
+ `Alexa`
+ `AMZN`
+ `Amazon`
+ `ASK`
+ `AWS`
+ `Custom`
+ `Dev`
 *Required*: Yes  
 *Pattern*: `^[a-zA-Z0-9]{2,64}::[a-zA-Z0-9]{2,64}::[a-zA-Z0-9]{2,64}$`

`description`  <a name="schema-properties-description"></a>
A short description of the resource. This will be displayed in the CloudFormation console.  
*Required*: Yes

`sourceUrl`  <a name="schema-properties-sourceUrl"></a>
The URL of the source code for this resource, if public.

`documentationUrl`  <a name="schema-properties-documentationurl"></a>
The URL of a page providing detailed documentation for this resource.  
While the resource schema itself should include complete and accurate property descriptions, the documentationURL property enables you to provide users with documentation that describes and explains the resource in more detail, including examples, use cases, and other detailed information.

`replacementStrategy`  <a name="schema-properties-replacementstrategy"></a>
The order of replacement when a resource update necessitates replacing the existing resource with a new resource. For example, updating a resource property that is listed in `createonlyProperties` results in a new resource being created to replace the existing resource.  
By default, when updating a resource that requires replacement, CloudFormation first creates the new resource, and then delete the old resource. However, some resources can only exist one at a time in a given account/region. For these resources, this attribute can be used to instruct CloudFormation to delete the existing resource before creating its replacement.  
For more information on how resources are updated, see [Update behaviors of stack resources](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/using-cfn-updating-stacks-update-behaviors.html) in the *CloudFormation User Guide*.  
*Valid values*: `create_then_delete` \$1 `delete_then_create`

`taggable`  <a name="schema-properties-taggable"></a>
Deprecated. Use the `tagging` element instead.

`tagging`  <a name="schema-properties-tagging"></a>
Contains properties that specify the resource type's support for tags.  
If your resource type does not support tagging, you must set `taggable` to `false` or your resource type will fail contract testing.    
`taggable`  <a name="schema-properties-tagging-taggable"></a>
Whether this resource type supports tagging.  
If your resource type does not support tagging, you must set `taggable` to `false` or your resource type will fail contract testing.  
The default is `true`.  
`tagOnCreate`  <a name="schema-properties-tagging-tagoncreate"></a>
Whether this resource type supports tagging resources upon creation.  
The default is `true`.  
`tagUpdatable`  <a name="schema-properties-tagging-tagupdatable"></a>
Whether this resource type supports updating tags during resource update operations.  
The default is `true`.  
`cloudFormationSystemTags`  <a name="schema-properties-tagging-cloudformationsystemtags"></a>
Whether this resource type supports CloudFormation system tags.  
The default is `true`.  
`tagProperty`  <a name="schema-properties-tagging-tagproperty"></a>
A reference to where you have defined the `Tags` property in this resource type schema.  
The default is `/properties/Tags`.

`definitions`  <a name="schema-properties-definitions"></a>
Use the `definitions` block to provide shared resource property schemas.  
It's considered a best practice is to use the `definitions` section to define schema elements that may be used at multiple points in your resource type schema. You can then use a JSON pointer to reference that element at the appropriate places in your resource type schema.

`properties`  <a name="schema-properties-properties"></a>
The properties of the resource.  
All properties of a resource must be expressed in the schema. Arbitrary inputs aren't allowed. A resource must contain at least one property.  
Nested properties are not allowed. Instead, define any nested properties in the `definitions` element, and use a `$ref` pointer to reference them in the desired property.  
*Required*: Yes    
`propertyName`  <a name="schema-properties-propertyname"></a>  
`insertionOrder`  <a name="schema-properties-properties-insertionorder"></a>
For properties of type `array`, set to `true` to specify that the order in which array items are specified must be honored, and that changing the order of the array will indicate a change in the property.  
The default is `true`.  
`dependencies`  <a name="schema-properties-properties-dependencies"></a>
Any properties that are required if this property is specified.  
`patternProperties`  <a name="schema-properties-properties-patternproperties"></a>
Use to specify a specification for key-value pairs.  

```
"type": "object",
"propertyNames": {
   "format": "regex"
}
```  
`properties`  <a name="schema-properties-properties-properties"></a>
*Minimum*: 1    
`patternProperties`  
*Pattern:* `^[A-Za-z0-9]{1,64}$`  
Specifies a pattern that properties must match to be valid.  
`allOf`  <a name="schema-properties-properties-allof"></a>
The property must contain all of the data structures define here.  
Contains a single schema. A list of schemas is not allowed.  
*Minimum*: 1  
`anyOf`  <a name="schema-properties-properties-anyof"></a>
The property can contain any number of the data structures define here.  
Contains a single schema. A list of schemas is not allowed.  
*Minimum*: 1  
`oneOf`  <a name="schema-properties-properties-oneof"></a>
The property must contain only one of the data structures define here.  
Contains a single schema. A list of schemas is not allowed.  
*Minimum*: 1  
`items`  <a name="schema-properties-properties-items"></a>
For properties of type array, defines the data structure of each array item.  
Contains a single schema. A list of schemas is not allowed.
In addition, the following elements, defined in [draft-07](https://json-schema.org/draft-07) of the [JSON Schema](https://json-schema.org/), are allowed in the `properties` object:  
+ \$1ref
+ \$1comment
+ title
+ description
+ examples
+ default
+ multipleOf
+ maximum
+ exclusiveMaximum
+ minimum
+ exclusiveMinimum
+ minLength
+ pattern
+ maxItems
+ minItems
+ uniqueItems
+ contains
+ maxProperties
+ required
+ const
+ enum
+ type
+ format

`propertyTransform`  <a name="schema-properties-propertytransform"></a>
One or more transforms to apply to the property value when comparing for drift. For more information, see [Preventing false drift detection results for resource types](https://docs.aws.amazon.com/cloudformation-cli/latest/userguide/resource-type-model-false-drift.html).

`remote`  <a name="schema-properties-remote"></a>
Reserved for CloudFormation use.

`readOnlyProperties`  <a name="schema-properties-readonlyproperties"></a>
Resource properties that can be returned by a `read` or `list` request, but can't be set by the user.  
*Type*: List of JSON pointers

`writeOnlyProperties`  <a name="schema-properties-writeonlyproperties"></a>
Resource properties that can be specified by the user, but can't be returned by a `read` or `list` request. Write-only properties are often used to contain passwords, secrets, or other sensitive data.  
*Type*: List of JSON pointers

`conditionalCreateOnlyProperties`  <a name="schema-properties-conditionalcreateonlyproperties"></a>
A list of JSON pointers for properties that can only be updated under certain conditions. For example, you can upgrade the engine version of an RDS DBInstance but you cannot downgrade it. When updating this property for a resource in a CloudFormation stack, the resource will be replaced if it cannot be updated.  
*Type*: List of JSON pointers

`nonPublicProperties`  <a name="schema-properties-nonpublicproperties"></a>
A list of JSON pointers for properties that are hidden. These properties will still be used but will not be visible  
*Type*: List of JSON pointers

`nonPublicDefinitions`  <a name="schema-properties-nonpublicdefinitions"></a>
A list of JSON pointers for definitions that are hidden. These definitions will still be used but will not be visible  
*Type*: List of JSON pointers

`createOnlyProperties`  <a name="schema-properties-createonlyproperties"></a>
Resource properties that can be specified by the user only during resource creation.  
Any property not explicitly listed in the `createOnlyProperties` element can be specified by the user during a resource update operation.
*Type*: List of JSON pointers

`deprecatedProperties`  <a name="schema-properties-deprecatedproperties"></a>
Resource properties that have been deprecated by the underlying service provider. These properties are still accepted in create and update operations. However they may be ignored, or converted to a consistent model on application. Deprecated properties are not guaranteed to be returned by read operations.  
*Type*: List of JSON pointers

`primaryIdentifier`  <a name="schema-properties-primaryidentifier"></a>
The uniquely identifier for an instance of this resource type. An identifier is a non-zero-length list of JSON pointers to properties that form a single key. An identifier can be a single or multiple properties to support composite-key identifiers.  
*Type*: List of JSON pointers  
*Required*: Yes

`additionalIdentifiers`  <a name="schema-properties-additionalidentifiers"></a>
An optional list of lists of supplementary identifiers, each of which uniquely identifies an instance of this resource type. An identifier can be a single property, or multiple properties to construct composite-key identifiers.  
*Type*: List of lists  
*Minimum*: 1

`handlers`  <a name="schema-properties-handlers"></a>
Specifies the provisioning operations which can be performed on this resource type. The handlers specified determine what provisioning actions CloudFormation takes with respect to the resource during various stack operations.  
+ If the resource type doesn't contain `create`, `read`, and `delete` handlers, CloudFormation can't actually provision the resource.
+ If the resource type doesn't contain an `update` handler, CloudFormation can't update the resource during stack update operations, and will instead replace it.
If your resource type calls AWS APIs in any of its handlers, you must create an *[IAM execution role](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles.html)* that includes the necessary permissions to call those AWS APIs, and provision that execution role in your account. For more information, see [Accessing AWS APIs from a Resource Type](https://docs.aws.amazon.com/cloudformation-cli/latest/userguide/resource-type-develop.html#resource-type-develop-executionrole).    
`create`  <a name="schema-properties-handlers-create"></a>  
permissions  <a name="schema-properties-handlers-create-permissions"></a>
A string array that specifies the AWS permissions needed to invoke the create handler.  
You must specify at least one permission for each handler.  
*Required*: Yes  
timeoutInMinutes  <a name="schema-properties-handlers-create-timeoutinminutes"></a>
An integer specifying the timeout for the entire operation to be interpreted by the invoker of the handler, in minutes.   
*Minimum*: 2  
*Maximum*: 2160  
*Default*: 120  
*Required*: No  
`read`  <a name="schema-properties-handlers-read"></a>  
`permissions`  <a name="schema-properties-handlers-read-permissions"></a>
A string array that specifies the AWS permissions needed to invoke the read handler.  
You must specify at least one permission for each handler.  
*Required*: Yes  
timeoutInMinutes  <a name="schema-properties-handlers-read-timeoutinminutes"></a>
An integer specifying the timeout for the entire operation to be interpreted by the invoker of the handler, in minutes.   
*Minimum*: 2  
*Maximum*: 2160  
*Default*: 120  
*Required*: No  
`update`  <a name="schema-properties-handlers-update"></a>  
permissions  <a name="schema-properties-handlers-update-permissions"></a>
A string array that specifies the AWS permissions needed to invoke the update handler.  
You must specify at least one permission for each handler.  
*Required*: Yes  
timeoutInMinutes  <a name="schema-properties-handlers-update-timeoutinminutes"></a>
An integer specifying the timeout for the entire operation to be interpreted by the invoker of the handler, in minutes.   
*Minimum*: 2  
*Maximum*: 2160  
*Default*: 120  
*Required*: No  
`delete`  <a name="schema-properties-handlers-delete"></a>  
permissions  <a name="schema-properties-handlers-delete-permissions"></a>
A string array that specifies the AWS permissions needed to invoke the delete handler.  
You must specify at least one permission for each handler.  
*Required*: Yes  
timeoutInMinutes  <a name="schema-properties-handlers-delete-timeoutinminutes"></a>
An integer specifying the timeout for the entire operation to be interpreted by the invoker of the handler, in minutes.   
*Minimum*: 2  
*Maximum*: 2160  
*Default*: 120  
*Required*: No  
`list`  <a name="schema-properties-handlers-list"></a>
The `list` handler must at least return the resource's primary identifier.    
permissions  <a name="schema-properties-handlers-list-permissions"></a>
A string array that specifies the AWS permissions needed to invoke the list handler.  
You must specify at least one permission for each handler.  
*Required*: Yes  
timeoutInMinutes  <a name="schema-properties-handlers-list-timeoutinminutes"></a>
An integer specifying the timeout for the entire operation to be interpreted by the invoker of the handler, in minutes.   
*Minimum*: 2  
*Maximum*: 2160  
*Default*: 120  
*Required*: No

`allOf`  <a name="schema-properties-allof"></a>
The resource must contain all of the data structures defined here.  
*Minimum*: 1

`anyOf`  <a name="schema-properties-anyof"></a>
The resource can contain any number of the data structures define here.  
*Minimum*: 1

`oneOf`  <a name="schema-properties-oneof"></a>
The resource must contain only one of the data structures define here.  
*Minimum*: 1

`resourceLink`  <a name="schema-properties-resourcelink"></a>
A template-able link to a resource instance. External service links must be absolute, HTTPS URIs.    
templateUri  <a name="schema-properties-resourcelink-templateuri"></a>
*Required*: Yes  
*Pattern*: `^(/|https:)`  
mappings  <a name="schema-properties-resourcelink-mappings"></a>
*Required*: Yes  
*Type*: List of JSON pointers

`typeConfiguration`  <a name="schema-properties-typeconfiguration"></a>
A type configuration schema that defines any properties that the user must specify for all instances of the extension in a given account and Region. For example, if your extension needs to access a third-party web service, you can include a configuration schema for the user to specify their credentials for that service.  
Your configuration definition must validate against the [provider configuration definition meta-schema](https://github.com/aws-cloudformation/cloudformation-cli/blob/master/src/rpdk/core/data/schema/provider.configuration.definition.schema.v1.json).  
When the user specifices a resource, they can sets the configuration. CloudFormation validates it against the configuration definition, and then saves this information at the Region level. From then on, CloudFormation can access that configuration schema during operations involving any instances of that extension in the Region. Configurations are available to CloudFormation during all resource operations, including `read` and `list` events that don't explicitly involve a stack template.  
The `CloudFormation` property name is reserved, and cannot be used to define any properties in your configuration definition.  
For more information, see [Defining the account-level configuration of an extension](https://docs.aws.amazon.com/cloudformation-cli/latest/userguide/resource-type-model.html#resource-type-howto-configuration).

# Patterns for modeling your resource types
<a name="resource-type-howtos"></a>

Use the following patterns to model the data structures of your resource types using the Resource Provider Schema.

## How to specify a property as dependent on another
<a name="resource-type-howto-dependencies"></a>

Use the `dependencies` element to specify if a property is required in order for another property to be specified. In the following example, if the user specifies a value for the `ResponseCode` property, they must also specify a value for `ResponsePagePath`, and vice versa. (Note that, as a best practice, this is also called out in the `description` of each property.)

```
"properties": {
"CustomErrorResponse": {
    "additionalProperties": false,
    "dependencies": {
        "ResponseCode": [
            "ResponsePagePath"
        ],
        "ResponsePagePath": [
            "ResponseCode"
        ]
    },
    "properties": {
        "ResponseCode": {
            "description": "The HTTP status code that you want CloudFront to return to the viewer along with the custom error page. If you specify a value for ResponseCode, you must also specify a value for ResponsePagePath.",
            "type": "integer"
        },
        "ResponsePagePath": {
            "description": "The path to the custom error page that you want CloudFront to return to a viewer when your origin returns the HTTP status code specified by ErrorCode. If you specify a value for ResponsePagePath, you must also specify a value for ResponseCode.",
            "type": "string"
        }
        . . . 
    },
    "type": "object" 
},
},
. . .
```

## How to define nested properties
<a name="resource-type-howto-nested-properties"></a>

It's considered a best practice is to use the `definitions` section to define schema elements that may be used at multiple points in your resource type schema. You can then use a JSON pointer to reference that element at the appropriate places in your resource type schema.

For example, define the reused element in the `definitions` section:

```
"definitions": {
    "AccountId": {
        "pattern": "^[0-9]{12}$",
        "type": "string"
    },
    . . . 
},
. . .
```

And then reference that definition where appropriate:

```
"AwsAccountNumber": {
    "description": "An AWS account that is included in the TrustedSigners complex type for this distribution.",
    "$ref": "#/definitions/AccountId"
},
    . . .
```

## Advanced: How to encapsulate complex logic
<a name="resource-type-howto-logic"></a>

Use the `allOf`, `oneOf`, or `anyOf` elements to encapsulate complex logic in your resource type schema.

In the example below, if `whitelist` is specified for the Forward property in your resource, then the `WhitelistedNames` property must also be specified.

```
"properties": {
"Cookies": {
    "oneOf": [
        {
            "additionalProperties": false,
            "properties": {
               "Forward": {
                    "description": "Specifies which cookies to forward to the origin for this cache behavior.",
                    "enum": [
                        "all",
                        "none"
                    ],
                    "type": "string"
                }
            },
            "required": [
                "Forward"
                ]
        },
     ],
        {
            "additionalProperties": false,
            "properties": {
                "Forward": {
                    "description": "Specifies which cookies to forward to the origin for this cache behavior.",
                    "enum": [
                        "whitelist"
                    ],
                    "type": "string"
                },
                "WhitelistedNames": {
                    "description": "Required if you specify whitelist for the value of Forward.",
                    "items": {
                       "type": "string"
                    },
                    "minItems": 1,
                    "type": "array"
                }
            },
            "required": [
                "Forward",
                "WhitelistedNames"
            ]
        },
    "type": "object"
    }
}
. . .
```

# Preventing false drift detection results for resource types
<a name="resource-type-model-false-drift"></a>

When CloudFormation performs drift detection on a resource, it looks up the value for each resource property as specified in the stack template, and compares that value with the current resource property value returned by the resource `read` handler. A resource is then considered to have drifted if one or more of its properties have been deleted, or had their value changed. In some cases, however, the resource may not be able to return the exact same value in the `read` handler as was specified in the stack template, even though the value is essentially the same and shouldn't be considered as drifted.

To prevent these cases from being incorrectly reported as drifted resources, you can specify a *property transform* in your resource schema. The property transform provides a way for CloudFormation to accurately compare the resource property value specified in the template with the value returned from the `read` handler. During drift detection, if CloudFormation finds a property where the template value differs from the value returned by the `read` handler, it determines if a property transform has been defined for that property in the resource schema. If it has, CloudFormation applies that property transform to the value specified in the template, and then compares it to the `read` handler value again. If these two values match, the property isn't considered to have drifted, and is marked as `IN_SYNC`.

For more information about drift detection, see [Detecting unmanaged configuration changes to stacks and resources](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/using-cfn-stack-drift.html) in the *CloudFormation User Guide*.

## Defining a property transform for drift detection operations
<a name="resource-type-model-false-drift-property-transform"></a>

Use the `propertyTransform` element to define a property transform for a given resource property.

```
"propertyTransform": { 
  "property_path": "transform"
}
```

Where:
+ *property\$1path* is the path to the resource property in the resource schema.
+ *transform* is the transform to perform on the resource property value specified in the stack template.

  Property transforms are written in [JSONata](https://docs.jsonata.org/overview.html), an open-source, lightweight query and transformation language for JSON data.

For example, consider the `[AWS::Route53::HostedZone](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-route53-hostedzone.html#cfn-route53-hostedzone-name) resource`. For the `[Name](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-route53-hostedzone.html#cfn-route53-hostedzone-name)` property, users can specify a domain name with or without a trailing `.` in their templates. However, assume the Route 53 service always returns the domain name with a trailing `.`. This means that if a user specified a domain name without the trailing `.` in their template, created the stack, and then performed drift detection on the stack, CloudFormation would erroneously report the `AWS::Route53::HostedZone` resource as drifted. To prevent this from happening, the resource developer would add a `propertyTransform` element to the resource schema to enable CloudFormation to determine if both property values were actually the same:

```
"propertyTransform": { 
  "/properties/Name": "$join([Name, \".\"])"
}
```

### Specifying multiple transforms for a property
<a name="resource-type-model-false-drift-property-transform-mulitple"></a>

You can specify multiple transforms for CloudFormation to attempt by using the `$OR` operator. If you specify multiple transforms, CloudFormation tries them all, in the order they're specified, until it finds one that results in the property values matching, or it has tried them all.

For example, for the following property transform, CloudFormation would attempt two transforms to determine whether the property value has actually drifted:
+ Append `.` to the template property value, and determine if the updated value now matches the property value returned by the resource `read` handler. If it does, CloudFormation reports the property as `IN_SYNC`. If not, CloudFormation performs the next transform.
+ Append the string `test` to the template property value, and determine if the updated value now matches the property value returned by the resource `read` handler. If it does, CloudFormation reports the property as `IN_SYNC`. If not, CloudFormation reports the property, and the resource, as `MODIFIED`.

```
"propertyTransform": { 
  "/properties/Name": "$join([Name, \".\"]) $OR $join([Name, \"test\"])"
}
```