Repository: getmoto/moto
Pull request #8556 (2025-02-03 11:31:07)

EC2: Require size/snapshot when creating EBS volume
Related to https://github.com/localstack/localstack/issues/11522


Patch:
diff --git a/moto/ec2/models/elastic_block_store.py b/moto/ec2/models/elastic_block_store.py
index e0c35e18e..27a028ffa 100644
--- a/moto/ec2/models/elastic_block_store.py
+++ b/moto/ec2/models/elastic_block_store.py
@@ -12,6 +12,7 @@ from ..exceptions import (
     InvalidVolumeAttachmentError,
     InvalidVolumeDetachmentError,
     InvalidVolumeIdError,
+    MissingParameterError,
     VolumeInUseError,
 )
 from ..utils import (
@@ -305,6 +306,10 @@ class EBSBackend:
                 size = snapshot.volume.size
             if snapshot.encrypted:
                 encrypted = snapshot.encrypted
+
+        if size is None:
+            raise MissingParameterError("size/snapshot")
+
         volume = Volume(
             self,
             volume_id=volume_id,
diff --git a/moto/rds/exceptions.py b/moto/rds/exceptions.py
index 181b5ba1c..8150687fc 100644
--- a/moto/rds/exceptions.py
+++ b/moto/rds/exceptions.py
@@ -1,23 +1,7 @@
-from jinja2 import Template
-
-from moto.core.exceptions import RESTError
-
-
-class RDSClientError(RESTError):
+class RDSClientError(Exception):
     def __init__(self, code: str, message: str):
-        super().__init__(error_type=code, message=message)
-        template = Template(
-            """
-        <ErrorResponse>
-            <Error>
-              <Code>{{ code }}</Code>
-              <Message>{{ message }}</Message>
-              <Type>Sender</Type>
-            </Error>
-            <RequestId>6876f774-7273-11e4-85dc-39e55ca848d1</RequestId>
-        </ErrorResponse>"""
-        )
-        self.description = template.render(code=code, message=message)
+        super().__init__(message)
+        self.code = code
 
 
 class DBInstanceNotFoundError(RDSClientError):
@@ -48,8 +32,6 @@ class DBSecurityGroupNotFoundError(RDSClientError):
 
 
 class DBSubnetGroupNotFoundError(RDSClientError):
-    code = 404
-
     def __init__(self, subnet_group_name: str):
         super().__init__(
             "DBSubnetGroupNotFoundFault", f"Subnet Group {subnet_group_name} not found."
diff --git a/moto/rds/models.py b/moto/rds/models.py
index 4f070b223..6f0aa2ce3 100644
--- a/moto/rds/models.py
+++ b/moto/rds/models.py
@@ -8,8 +8,6 @@ from functools import lru_cache
 from re import compile as re_compile
 from typing import TYPE_CHECKING, Any, Dict, Iterable, List, Optional, Tuple, Union
 
-from jinja2 import Template
-
 from moto.core.base_backend import BackendDict, BaseBackend
 from moto.core.common_models import BaseModel, CloudFormationModel
 from moto.core.utils import iso_8601_datetime_with_milliseconds
@@ -168,26 +166,6 @@ class ProxyTargetGroup(RDSBaseModel):
     def name(self) -> str:
         return self._name
 
-    def to_xml(self) -> str:
-        template = Template("""<DBProxyName>{{ group.proxy_name }}</DBProxyName>
-      <TargetGroupName>{{ group.group_name }}</TargetGroupName>
-      <TargetGroupArn>{{ group.arn }}</TargetGroupArn>
-      <IsDefault>true</IsDefault>
-      <Status>available</Status>
-      <ConnectionPoolConfig>
-        <MaxConnectionsPercent>{{ group.max_connections }}</MaxConnectionsPercent>
-        <MaxIdleConnectionsPercent>{{ group.max_idle_connections }}</MaxIdleConnectionsPercent>
-        <ConnectionBorrowTimeout>{{ group.borrow_timeout }}</ConnectionBorrowTimeout>
-        <SessionPinningFilters>
-        {% for filter in group.session_pinning_filters %}
-        <member>{{ filter }}</member>
-        {% endfor %}
-        </SessionPinningFilters>
-      </ConnectionPoolConfig>
-      <CreatedDate>{{ group.created_date }}</CreatedDate>
-      <UpdatedDate>{{ group.updated_date }}</UpdatedDate>""")
-        return template.render(group=self)
-
 
 class GlobalCluster(RDSBaseModel):
     resource_type = "global-cluster"
@@ -233,37 +211,6 @@ class GlobalCluster(RDSBaseModel):
     def global_cluster_arn(self) -> str:
         return self.arn
 
-    def to_xml(self) -> str:
-        template = Template(
-            """
-          <GlobalClusterIdentifier>{{ cluster.global_cluster_identifier }}</GlobalClusterIdentifier>
-          <GlobalClusterResourceId>{{ cluster.global_cluster_resource_id }}</GlobalClusterResourceId>
-          <GlobalClusterArn>{{ cluster.global_cluster_arn }}</GlobalClusterArn>
-          <Engine>{{ cluster.engine }}</Engine>
-          <Status>available</Status>
-          <EngineVersion>{{ cluster.engine_version }}</EngineVersion>
-          <StorageEncrypted>{{ 'true' if cluster.storage_encrypted else 'false' }}</StorageEncrypted>
-          <DeletionProtection>{{ 'true' if cluster.deletion_protection else 'false' }}</DeletionProtection>
-          <GlobalClusterMembers>
-          {% for cluster_member in cluster.members %}
-          <GlobalClusterMember>
-            <DBClusterArn>{{ cluster_member.arn }}</DBClusterArn>
-            <IsWriter>{{ 'true' if cluster_member.is_writer else 'false' }}</IsWriter>
-            {% if not cluster_member.is_writer %}<GlobalWriteForwardingStatus>disabled</GlobalWriteForwardingStatus>{% endif %}
-                <Readers>
-                    {% if cluster_member.is_writer %}
-                        {% for reader in cluster.members %}
-                            {% if not reader.is_writer %}<Reader>{{ reader.db_cluster_arn }}</Reader>{% endif %}
-                        {% endfor %}
-                    {% endif %}
-                </Readers>
-          </GlobalClusterMember>
-          {% endfor %}
-          </GlobalClusterMembers>
-          """
-        )
-        return template.render(cluster=self)
-
 
 class DBCluster(RDSBaseModel):
     SUPPORTED_FILTERS = {
@@ -517,123 +464,6 @@ class DBCluster(RDSBaseModel):
         cfg["enable_http_endpoint"] = cfg.pop("_enable_http_endpoint")
         return cfg
 
-    def to_xml(self, initial: bool = False) -> str:
-        status = "creating" if initial else self.status
-        template = Template(
-            """<DBCluster>
-              <AllocatedStorage>{{ cluster.allocated_storage }}</AllocatedStorage>
-              <AvailabilityZones>
-              {% for zone in cluster.availability_zones %}
-                  <AvailabilityZone>{{ zone }}</AvailabilityZone>
-              {% endfor %}
-              </AvailabilityZones>
-              <BackupRetentionPeriod>{{ cluster.backup_retention_period }}</BackupRetentionPeriod>
-              <BacktrackWindow>{{ cluster.backtrack_window }}</BacktrackWindow>
-              <DBInstanceStatus>{{ cluster.status }}</DBInstanceStatus>
-              {% if cluster.db_name %}<DatabaseName>{{ cluster.db_name }}</DatabaseName>{% endif %}
-              {% if cluster.kms_key_id %}<KmsKeyId>{{ cluster.kms_key_id }}</KmsKeyId>{% endif %}
-              {% if cluster.network_type %}<NetworkType>{{ cluster.network_type }}</NetworkType>{% endif %}
-              <DBClusterIdentifier>{{ cluster.db_cluster_identifier }}</DBClusterIdentifier>
-              <DBClusterParameterGroup>{{ cluster.parameter_group }}</DBClusterParameterGroup>
-              <DBSubnetGroup>{{ cluster.subnet_group }}</DBSubnetGroup>
-              <ClusterCreateTime>{{ cluster.cluster_create_time }}</ClusterCreateTime>
-              <EarliestRestorableTime>{{ cluster.earliest_restorable_time }}</EarliestRestorableTime>
-              <Engine>{{ cluster.engine }}</Engine>
-              <Status>{{ status }}</Status>
-              <Endpoint>{{ cluster.endpoint }}</Endpoint>
-              <ReaderEndpoint>{{ cluster.reader_endpoint }}</ReaderEndpoint>
-              <MultiAZ>{{ 'true' if cluster.is_multi_az else 'false' }}</MultiAZ>
-              <EngineVersion>{{ cluster.engine_version }}</EngineVersion>
-              <Port>{{ cluster.port }}</Port>
-              {% if cluster.iops %}
-                <Iops>{{ cluster.iops }}</Iops>
-                <StorageType>io1</StorageType>
-              {% endif %}
-              {% if cluster.db_cluster_instance_class %}<DBClusterInstanceClass>{{ cluster.db_cluster_instance_class }}</DBClusterInstanceClass>{% endif %}
-              <MasterUsername>{{ cluster.master_username }}</MasterUsername>
-              <PreferredBackupWindow>{{ cluster.preferred_backup_window }}</PreferredBackupWindow>
-              <PreferredMaintenanceWindow>{{ cluster.preferred_maintenance_window }}</PreferredMaintenanceWindow>
-              <ReadReplicaIdentifiers>
-              {% for replica_id in cluster.read_replica_identifiers %}
-                <ReadReplicaIdentifier>{{ replica_id }}</ReadReplicaIdentifier>
-              {% endfor %}
-              </ReadReplicaIdentifiers>
-              <DBClusterMembers>
-              {% for member in cluster.cluster_members %}
-              <DBClusterMember>
-                <DBInstanceIdentifier>{{ member }}</DBInstanceIdentifier>
-                <IsClusterWriter>true</IsClusterWriter>
-                <DBClusterParameterGroupStatus>in-sync</DBClusterParameterGroupStatus>
-                <PromotionTier>1</PromotionTier>
-              </DBClusterMember>
-              {% endfor %}
-              </DBClusterMembers>
-              <VpcSecurityGroups>
-              {% for id in cluster.vpc_security_group_ids %}
-                  <VpcSecurityGroup>
-                      <VpcSecurityGroupId>{{ id }}</VpcSecurityGroupId>
-                      <Status>active</Status>
-                  </VpcSecurityGroup>
-              {% endfor %}
-              </VpcSecurityGroups>
-              <HostedZoneId>{{ cluster.hosted_zone_id }}</HostedZoneId>
-              <StorageEncrypted>{{ 'true' if cluster.storage_encrypted else 'false' }}</StorageEncrypted>
-              <GlobalWriteForwardingRequested>{{ 'true' if cluster.global_write_forwarding_requested else 'false'  }}</GlobalWriteForwardingRequested>
-              <DbClusterResourceId>{{ cluster.resource_id }}</DbClusterResourceId>
-              <DBClusterArn>{{ cluster.db_cluster_arn }}</DBClusterArn>
-              <AssociatedRoles></AssociatedRoles>
-              <IAMDatabaseAuthenticationEnabled>{{ 'true' if cluster.iam_auth else 'false' }}</IAMDatabaseAuthenticationEnabled>
-              <EngineMode>{{ cluster.engine_mode }}</EngineMode>
-              <DeletionProtection>{{ 'true' if cluster.deletion_protection else 'false' }}</DeletionProtection>
-              <HttpEndpointEnabled>{{ 'true' if cluster.enable_http_endpoint else 'false' }}</HttpEndpointEnabled>
-              <CopyTagsToSnapshot>{{ 'true' if cluster.copy_tags_to_snapshot else 'false' }}</CopyTagsToSnapshot>
-              <CrossAccountClone>false</CrossAccountClone>
-              <DomainMemberships></DomainMemberships>
-              <EnabledCloudwatchLogsExports>
-              {% for export in cluster.enabled_cloudwatch_logs_exports %}
-              <member>{{ export }}</member>
-              {% endfor %}
-              </EnabledCloudwatchLogsExports>
-              <TagList>
-              {%- for tag in cluster.tags -%}
-                <Tag>
-                  <Key>{{ tag['Key'] }}</Key>
-                  <Value>{{ tag['Value'] }}</Value>
-                </Tag>
-              {%- endfor -%}
-              </TagList>
-              {% if cluster.scaling_configuration %}
-              <ScalingConfigurationInfo>
-                {% if "min_capacity" in cluster.scaling_configuration %}<MinCapacity>{{ cluster.scaling_configuration["min_capacity"] }}</MinCapacity>{% endif %}
-                {% if "max_capacity" in cluster.scaling_configuration %}<MaxCapacity>{{ cluster.scaling_configuration["max_capacity"] }}</MaxCapacity>{% endif %}
-                {% if "auto_pause" in cluster.scaling_configuration %}<AutoPause>{{ cluster.scaling_configuration["auto_pause"] }}</AutoPause>{% endif %}
-                {% if "seconds_until_auto_pause" in cluster.scaling_configuration %}<SecondsUntilAutoPause>{{ cluster.scaling_configuration["seconds_until_auto_pause"] }}</SecondsUntilAutoPause>{% endif %}
-                {% if "timeout_action" in cluster.scaling_configuration %}<TimeoutAction>{{ cluster.scaling_configuration["timeout_action"] }}</TimeoutAction>{% endif %}
-                {% if "seconds_before_timeout" in cluster.scaling_configuration %}<SecondsBeforeTimeout>{{ cluster.scaling_configuration["seconds_before_timeout"] }}</SecondsBeforeTimeout>{% endif %}
-              </ScalingConfigurationInfo>
-              {% endif %}
-              {% if cluster.serverless_v2_scaling_configuration %}
-              <ServerlessV2ScalingConfiguration>
-                {% if "MinCapacity" in cluster.serverless_v2_scaling_configuration %}<MinCapacity>{{ cluster.serverless_v2_scaling_configuration["MinCapacity"] }}</MinCapacity>{% endif %}
-                {% if "MaxCapacity" in cluster.serverless_v2_scaling_configuration %}<MaxCapacity>{{ cluster.serverless_v2_scaling_configuration["MaxCapacity"] }}</MaxCapacity>{% endif %}
-              </ServerlessV2ScalingConfiguration>
-              {% endif %}
-              {%- if cluster.global_cluster_identifier -%}
-              <GlobalClusterIdentifier>{{ cluster.global_cluster_identifier }}</GlobalClusterIdentifier>
-              {%- endif -%}
-              {%- if cluster.replication_source_identifier -%}<ReplicationSourceIdentifier>{{ cluster.replication_source_identifier }}</ReplicationSourceIdentifier>{%- endif -%}
-              {%- if cluster.manage_master_user_password -%}
-              <MasterUserSecret>
-                {% set master_user_secret = cluster.master_user_secret() %}
-                {% if "secret_arn" in master_user_secret %}<SecretArn>{{ master_user_secret["secret_arn"] }}</SecretArn>{% endif %}
-                {% if "secret_status" in master_user_secret %}<SecretStatus>{{ master_user_secret["secret_status"] }}</SecretStatus>{% endif %}
-                {% if "kms_key_id" in master_user_secret %}<KmsKeyId>{{ master_user_secret["kms_key_id"] }}</KmsKeyId>{% endif %}
-              </MasterUserSecret>
-              {%- endif -%}
-            </DBCluster>"""
-        )
-        return template.render(cluster=self, status=status)
-
     @staticmethod
     def default_engine_version(engine: str) -> str:
         return {
@@ -715,41 +545,6 @@ class DBClusterSnapshot(RDSBaseModel):
     def snapshot_arn(self) -> str:
         return self.arn
 
-    def to_xml(self) -> str:
-        template = Template(
-            """
-            <DBClusterSnapshot>
-                <DBClusterSnapshotIdentifier>{{ snapshot.snapshot_id }}</DBClusterSnapshotIdentifier>
-                <SnapshotCreateTime>{{ snapshot.created_at }}</SnapshotCreateTime>
-                <DBClusterIdentifier>{{ cluster.db_cluster_identifier }}</DBClusterIdentifier>
-                <ClusterCreateTime>{{ snapshot.created_at }}</ClusterCreateTime>
-                <PercentProgress>{{ 100 }}</PercentProgress>
-                <AllocatedStorage>{{ cluster.allocated_storage }}</AllocatedStorage>
-                <MasterUsername>{{ cluster.master_username }}</MasterUsername>
-                <Port>{{ cluster.port }}</Port>
-                <Engine>{{ cluster.engine }}</Engine>
-                <Status>{{ snapshot.status }}</Status>
-                <SnapshotType>{{ snapshot.snapshot_type }}</SnapshotType>
-                <DBClusterSnapshotArn>{{ snapshot.snapshot_arn }}</DBClusterSnapshotArn>
-                <SourceRegion>{{ cluster.region }}</SourceRegion>
-                {% if cluster.iops %}
-                <Iops>{{ cluster.iops }}</Iops>
-                <StorageType>io1</StorageType>
-                {% else %}
-                <StorageType>{{ cluster.storage_type }}</StorageType>
-                {% endif %}
-                <TagList>
-                {%- for tag in snapshot.tags -%}
-                    <Tag><Key>{{ tag['Key'] }}</Key><Value>{{ tag['Value'] }}</Value></Tag>
-                {%- endfor -%}
-                </TagList>
-                <Timezone></Timezone>
-                <LicenseModel>{{ cluster.license_model }}</LicenseModel>
-            </DBClusterSnapshot>
-            """
-        )
-        return template.render(snapshot=self, cluster=self.cluster)
-
 
 class DBInstance(CloudFormationModel, RDSBaseModel):
     SUPPORTED_FILTERS = {
@@ -962,140 +757,6 @@ class DBInstance(CloudFormationModel, RDSBaseModel):
             else f"arn:{self.partition}:kms:{self.region}:{self.account_id}:key/{self.name}",
         }
 
-    def to_xml(self) -> str:
-        template = Template(
-            """<DBInstance>
-              <AvailabilityZone>{{ database.availability_zone }}</AvailabilityZone>
-              <BackupRetentionPeriod>{{ database.backup_retention_period }}</BackupRetentionPeriod>
-              <DBInstanceStatus>{{ database.status }}</DBInstanceStatus>
-              {% if database.db_name %}<DBName>{{ database.db_name }}</DBName>{% endif %}
-              <MultiAZ>{{ 'true' if database.multi_az else 'false' }}</MultiAZ>
-              <VpcSecurityGroups>
-                {% for vpc_security_group_id in database.vpc_security_group_ids %}
-                <VpcSecurityGroupMembership>
-                  <Status>active</Status>
-                  <VpcSecurityGroupId>{{ vpc_security_group_id }}</VpcSecurityGroupId>
-                </VpcSecurityGroupMembership>
-                {% endfor %}
-              </VpcSecurityGroups>
-              {% if database.db_cluster_identifier %}<DBClusterIdentifier>{{ database.db_cluster_identifier }}</DBClusterIdentifier>{% endif %}
-              <DBInstanceIdentifier>{{ database.db_instance_identifier }}</DBInstanceIdentifier>
-              <DbiResourceId>{{ database.dbi_resource_id }}</DbiResourceId>
-              <InstanceCreateTime>{{ database.instance_create_time }}</InstanceCreateTime>
-              <PreferredBackupWindow>{{ database.preferred_backup_window }}</PreferredBackupWindow>
-              <PreferredMaintenanceWindow>{{ database.preferred_maintenance_window }}</PreferredMaintenanceWindow>
-              <ReadReplicaDBInstanceIdentifiers>
-                {% for replica_id in database.replicas %}
-                    <ReadReplicaDBInstanceIdentifier>{{ replica_id }}</ReadReplicaDBInstanceIdentifier>
-                {% endfor %}
-              </ReadReplicaDBInstanceIdentifiers>
-              <StatusInfos>
-                {% if database.is_replica %}
-                <DBInstanceStatusInfo>
-                    <StatusType>read replication</StatusType>
-                    <Status>replicating</Status>
-                    <Normal>true</Normal>
-                    <Message></Message>
-                </DBInstanceStatusInfo>
-                {% endif %}
-              </StatusInfos>
-              <EnabledCloudwatchLogsExports>
-              {% for export in database.enabled_cloudwatch_logs_exports %}
-              <member>{{ export }}</member>
-              {% endfor %}
-              </EnabledCloudwatchLogsExports>
-              {% if database.is_replica %}
-              <ReadReplicaSourceDBInstanceIdentifier>{{ database.source_db_identifier }}</ReadReplicaSourceDBInstanceIdentifier>
-              {% endif %}
-              <Engine>{{ database.engine }}</Engine>
-              <IAMDatabaseAuthenticationEnabled>{{'true' if database.enable_iam_database_authentication else 'false' }}</IAMDatabaseAuthenticationEnabled>
-              <LicenseModel>{{ database.license_model }}</LicenseModel>
-              <EngineVersion>{{ database.engine_version }}</EngineVersion>
-              <OptionGroupMemberships>
-                <OptionGroupMembership>
-                  <OptionGroupName>{{ database.option_group_name }}</OptionGroupName>
-                  <Status>in-sync</Status>
-                </OptionGroupMembership>
-              </OptionGroupMemberships>
-              <DBParameterGroups>
-                {% for db_parameter_group in database.db_parameter_groups() %}
-                <DBParameterGroup>
-                  <ParameterApplyStatus>in-sync</ParameterApplyStatus>
-                  <DBParameterGroupName>{{ db_parameter_group.name }}</DBParameterGroupName>
-                </DBParameterGroup>
-                {% endfor %}
-              </DBParameterGroups>
-              <DBSecurityGroups>
-                {% for security_group in database.security_groups %}
-                <DBSecurityGroup>
-                  <Status>active</Status>
-                  <DBSecurityGroupName>{{ security_group }}</DBSecurityGroupName>
-                </DBSecurityGroup>
-                {% endfor %}
-              </DBSecurityGroups>
-              {% if database.db_subnet_group %}
-              <DBSubnetGroup>
-                <DBSubnetGroupName>{{ database.db_subnet_group.subnet_name }}</DBSubnetGroupName>
-                <DBSubnetGroupDescription>{{ database.db_subnet_group.description }}</DBSubnetGroupDescription>
-                <SubnetGroupStatus>{{ database.db_subnet_group.status }}</SubnetGroupStatus>
-                <Subnets>
-                    {% for subnet in database.db_subnet_group.subnets %}
-                    <Subnet>
-                      <SubnetStatus>Active</SubnetStatus>
-                      <SubnetIdentifier>{{ subnet.id }}</SubnetIdentifier>
-                      <SubnetAvailabilityZone>
-                        <Name>{{ subnet.availability_zone }}</Name>
-                        <ProvisionedIopsCapable>false</ProvisionedIopsCapable>
-                      </SubnetAvailabilityZone>
-                    </Subnet>
-                    {% endfor %}
-                </Subnets>
-                <VpcId>{{ database.db_subnet_group.vpc_id }}</VpcId>
-              </DBSubnetGroup>
-              {% endif %}
-              <PubliclyAccessible>{{ 'true' if database.publicly_accessible else 'false' }}</PubliclyAccessible>
-              <CopyTagsToSnapshot>{{ 'true' if database.copy_tags_to_snapshot else 'false' }}</CopyTagsToSnapshot>
-              <AutoMinorVersionUpgrade>{{ 'true' if database.auto_minor_version_upgrade else 'false' }}</AutoMinorVersionUpgrade>
-              <AllocatedStorage>{{ database.allocated_storage }}</AllocatedStorage>
-              <StorageEncrypted>{{ 'true' if database.storage_encrypted else 'false' }}</StorageEncrypted>
-              {% if database.kms_key_id %}
-              <KmsKeyId>{{ database.kms_key_id }}</KmsKeyId>
-              {% endif %}
-              {% if database.iops %}
-              <Iops>{{ database.iops }}</Iops>
-              <StorageType>io1</StorageType>
-              {% else %}
-              <StorageType>{{ database.storage_type }}</StorageType>
-              {% endif %}
-              <DBInstanceClass>{{ database.db_instance_class }}</DBInstanceClass>
-              <MasterUsername>{{ database.master_username }}</MasterUsername>
-              <Endpoint>
-                <Address>{{ database.address }}</Address>
-                <Port>{{ database.port }}</Port>
-              </Endpoint>
-              <DbInstancePort>{{ database.port }}</DbInstancePort>
-              <DBInstanceArn>{{ database.db_instance_arn }}</DBInstanceArn>
-              <TagList>
-              {%- for tag in database.tags -%}
-                <Tag>
-                  <Key>{{ tag['Key'] }}</Key>
-                  <Value>{{ tag['Value'] }}</Value>
-                </Tag>
-              {%- endfor -%}
-              </TagList>
-              <DeletionProtection>{{ 'true' if database.deletion_protection else 'false' }}</DeletionProtection>
-              {%- if database.manage_master_user_password -%}
-              <MasterUserSecret>
-                {% set master_user_secret = database.master_user_secret() %}
-                {% if "secret_arn" in master_user_secret %}<SecretArn>{{ master_user_secret["secret_arn"] }}</SecretArn>{% endif %}
-                {% if "secret_status" in master_user_secret %}<SecretStatus>{{ master_user_secret["secret_status"] }}</SecretStatus>{% endif %}
-                {% if "kms_key_id" in master_user_secret %}<KmsKeyId>{{ master_user_secret["kms_key_id"] }}</KmsKeyId>{% endif %}
-              </MasterUserSecret>
-              {%- endif -%}
-            </DBInstance>"""
-        )
-        return template.render(database=self)
-
     @property
     def address(self) -> str:
         return (
@@ -1299,57 +960,6 @@ class DBSnapshot(RDSBaseModel):
     def snapshot_arn(self) -> str:
         return self.arn
 
-    def to_xml(self) -> str:
-        template = Template(
-            """<DBSnapshot>
-              <DBSnapshotIdentifier>{{ snapshot.snapshot_id }}</DBSnapshotIdentifier>
-              <DBInstanceIdentifier>{{ database.db_instance_identifier }}</DBInstanceIdentifier>
-              <DbiResourceId>{{ database.dbi_resource_id }}</DbiResourceId>
-              <SnapshotCreateTime>{{ snapshot.created_at }}</SnapshotCreateTime>
-              <Engine>{{ database.engine }}</Engine>
-              <AllocatedStorage>{{ database.allocated_storage }}</AllocatedStorage>
-              <Status>{{ snapshot.status }}</Status>
-              <Port>{{ database.port }}</Port>
-              <AvailabilityZone>{{ database.availability_zone }}</AvailabilityZone>
-              <VpcId>{{ database.db_subnet_group.vpc_id }}</VpcId>
-              <InstanceCreateTime>{{ snapshot.created_at }}</InstanceCreateTime>
-              {% if database.master_username %}
-              <MasterUsername>{{ database.master_username }}</MasterUsername>
-              {% endif %}
-              <EngineVersion>{{ database.engine_version }}</EngineVersion>
-              {% if database.license_model %}
-              <LicenseModel>{{ database.license_model }}</LicenseModel>
-              {% endif %}
-              <SnapshotType>{{ snapshot.snapshot_type }}</SnapshotType>
-              {% if database.iops %}
-              <Iops>{{ database.iops }}</Iops>
-              <StorageType>io1</StorageType>
-              {% else %}
-              <StorageType>{{ database.storage_type }}</StorageType>
-              {% endif %}
-              <OptionGroupName>{{ database.option_group_name }}</OptionGroupName>
-              <PercentProgress>{{ 100 }}</PercentProgress>
-              <SourceRegion>{{ database.region }}</SourceRegion>
-              <SourceDBSnapshotIdentifier></SourceDBSnapshotIdentifier>
-              <TagList>
-              {%- for tag in snapshot.tags -%}
-                <Tag><Key>{{ tag['Key'] }}</Key><Value>{{ tag['Value'] }}</Value></Tag>
-              {%- endfor -%}
-              </TagList>
-              <TdeCredentialArn></TdeCredentialArn>
-              <Encrypted>{{ database.storage_encrypted }}</Encrypted>
-              {% if database.kms_key_id %}
-              <KmsKeyId>{{ database.kms_key_id }}</KmsKeyId>
-              {% endif %}
-              <DBSnapshotArn>{{ snapshot.snapshot_arn }}</DBSnapshotArn>
-              <Timezone></Timezone>
-              {% if database.enable_iam_database_authentication %}
-              <IAMDatabaseAuthenticationEnabled>{{ 'true' if database.enable_iam_database_authentication else 'false' }}</IAMDatabaseAuthenticationEnabled>
-              {% endif %}
-            </DBSnapshot>"""
-        )
-        return template.render(snapshot=self, database=self.database)
-
 
 class ExportTask(BaseModel):
     def __init__(
@@ -1371,35 +981,6 @@ class ExportTask(BaseModel):
         self.created_at = iso_8601_datetime_with_milliseconds()
         self.source_type = "SNAPSHOT" if type(snapshot) is DBSnapshot else "CLUSTER"
 
-    def to_xml(self) -> str:
-        template = Template(
-            """
-            <ExportTaskIdentifier>{{ task.export_task_identifier }}</ExportTaskIdentifier>
-            <SourceArn>{{ snapshot.snapshot_arn }}</SourceArn>
-            <TaskStartTime>{{ task.created_at }}</TaskStartTime>
-            <TaskEndTime>{{ task.created_at }}</TaskEndTime>
-            <SnapshotTime>{{ snapshot.created_at }}</SnapshotTime>
-            <S3Bucket>{{ task.s3_bucket_name }}</S3Bucket>
-            <S3Prefix>{{ task.s3_prefix }}</S3Prefix>
-            <IamRoleArn>{{ task.iam_role_arn }}</IamRoleArn>
-            <KmsKeyId>{{ task.kms_key_id }}</KmsKeyId>
-            {%- if task.export_only -%}
-            <ExportOnly>
-                {%- for table in task.export_only -%}
-                    <member>{{ table }}</member>
-                {%- endfor -%}
-            </ExportOnly>
-            {%- endif -%}
-            <Status>{{ task.status }}</Status>
-            <PercentProgress>{{ 100 }}</PercentProgress>
-            <TotalExtractedDataInGB>{{ 1 }}</TotalExtractedDataInGB>
-            <FailureCause></FailureCause>
-            <WarningMessage></WarningMessage>
-            <SourceType>{{ task.source_type }}</SourceType>
-            """
-        )
-        return template.render(task=self, snapshot=self.snapshot)
-
 
 class EventSubscription(RDSBaseModel):
     resource_type = "es"
@@ -1422,38 +1003,6 @@ class EventSubscription(RDSBaseModel):
     def name(self) -> str:
         return self.subscription_name
 
-    def to_xml(self) -> str:
-        template = Template(
-            """
-            <EventSubscription>
-              <CustomerAwsId>{{ subscription.account_id }}</CustomerAwsId>
-              <CustSubscriptionId>{{ subscription.name }}</CustSubscriptionId>
-              <SnsTopicArn>{{ subscription.sns_topic_arn }}</SnsTopicArn>
-              <SubscriptionCreationTime>{{ subscription.created_at }}</SubscriptionCreationTime>
-              <SourceType>{{ subscription.source_type }}</SourceType>
-              <SourceIdsList>
-                {%- for source_id in subscription.source_ids -%}
-                  <SourceId>{{ source_id }}</SourceId>
-                {%- endfor -%}
-              </SourceIdsList>
-              <EventCategoriesList>
-                {%- for category in subscription.event_categories -%}
-                  <EventCategory>{{ category }}</EventCategory>
-                {%- endfor -%}
-              </EventCategoriesList>
-              <Status>{{ subscription.status }}</Status>
-              <Enabled>{{ 'true' if subscription.enabled else 'false' }}</Enabled>
-              <EventSubscriptionArn>{{ subscription.arn }}</EventSubscriptionArn>
-              <TagList>
-              {%- for tag in subscription.tags -%}
-                <Tag><Key>{{ tag['Key'] }}</Key><Value>{{ tag['Value'] }}</Value></Tag>
-              {%- endfor -%}
-              </TagList>
-            </EventSubscription>
-            """
-        )
-        return template.render(subscription=self)
-
 
 class DBSecurityGroup(CloudFormationModel, RDSBaseModel):
     resource_type = "secgrp"
@@ -1478,36 +1027,6 @@ class DBSecurityGroup(CloudFormationModel, RDSBaseModel):
     def name(self) -> str:
         return self.group_name
 
-    def to_xml(self) -> str:
-        template = Template(
-            """<DBSecurityGroup>
-            <EC2SecurityGroups>
-            {% for security_group in security_group.ec2_security_groups %}
-                <EC2SecurityGroup>
-                    <EC2SecurityGroupId>{{ security_group.id }}</EC2SecurityGroupId>
-                    <EC2SecurityGroupName>{{ security_group.group_name }}</EC2SecurityGroupName>
-                    <EC2SecurityGroupOwnerId>{{ security_group.account_id }}</EC2SecurityGroupOwnerId>
-                    <Status>authorized</Status>
-                </EC2SecurityGroup>
-            {% endfor %}
-            </EC2SecurityGroups>
-
-            <DBSecurityGroupDescription>{{ security_group.description }}</DBSecurityGroupDescription>
-            <IPRanges>
-            {% for ip_range in security_group.ip_ranges %}
-                <IPRange>
-                    <CIDRIP>{{ ip_range }}</CIDRIP>
-                    <Status>authorized</Status>
-                </IPRange>
-            {% endfor %}
-            </IPRanges>
-            <OwnerId>{{ security_group.ownder_id }}</OwnerId>
-            <DBSecurityGroupName>{{ security_group.name }}</DBSecurityGroupName>
-            <DBSecurityGroupArn>{{ security_group.arn }}</DBSecurityGroupArn>
-        </DBSecurityGroup>"""
-        )
-        return template.render(security_group=self)
-
     def authorize_cidr(self, cidr_ip: str) -> None:
         self.ip_ranges.append(cidr_ip)
 
@@ -1583,30 +1102,6 @@ class DBSubnetGroup(CloudFormationModel, RDSBaseModel):
     def name(self) -> str:
         return self.subnet_name
 
-    def to_xml(self) -> str:
-        template = Template(
-            """<DBSubnetGroup>
-              <VpcId>{{ subnet_group.vpc_id }}</VpcId>
-              <SubnetGroupStatus>{{ subnet_group.status }}</SubnetGroupStatus>
-              <DBSubnetGroupDescription>{{ subnet_group.description }}</DBSubnetGroupDescription>
-              <DBSubnetGroupName>{{ subnet_group.name }}</DBSubnetGroupName>
-              <DBSubnetGroupArn>{{ subnet_group.arn }}</DBSubnetGroupArn>
-              <Subnets>
-                {% for subnet in subnet_group.subnets %}
-                <Subnet>
-                  <SubnetStatus>Active</SubnetStatus>
-                  <SubnetIdentifier>{{ subnet.id }}</SubnetIdentifier>
-                  <SubnetAvailabilityZone>
-                    <Name>{{ subnet.availability_zone }}</Name>
-                    <ProvisionedIopsCapable>false</ProvisionedIopsCapable>
-                  </SubnetAvailabilityZone>
-                </Subnet>
-                {% endfor %}
-              </Subnets>
-            </DBSubnetGroup>"""
-        )
-        return template.render(subnet_group=self)
-
     @staticmethod
     def cloudformation_name_type() -> str:
         return "DBSubnetGroupName"
@@ -1728,49 +1223,6 @@ class DBProxy(RDSBaseModel):
     def arn(self) -> str:
         return f"arn:{self.partition}:rds:{self.region}:{self.account_id}:{self.resource_type}:{self.unique_id}"
 
-    def to_xml(self) -> str:
-        template = Template(
-            """
-                <RequireTLS>{{ dbproxy.require_tls }}</RequireTLS>
-                <VpcSecurityGroupIds>
-                {% if dbproxy.vpc_security_group_ids %}
-                  {% for sg in dbproxy.vpc_security_group_ids %}
-                    <member>{{ sg }}</member>
-                  {% endfor %}
-                {% endif %}
-                </VpcSecurityGroupIds>
-                <Auth>
-                  {% for auth in dbproxy.auth %}
-                    <member>
-                        <Description>{{ auth["Description"] }}</Description>
-                        <UserName>{{ auth["UserName"] }}</UserName>
-                        <AuthScheme>{{ auth["AuthScheme"] }}</AuthScheme>
-                        <SecretArn>{{ auth["SecretArn"] }}</SecretArn>
-                        <IAMAuth>{{ auth["IAMAuth"] }}</IAMAuth>
-                        <ClientPasswordAuthType>{{ auth["ClientPasswordAuthType"] }}</ClientPasswordAuthType>
-                    </member>
-                  {% endfor %}
-                </Auth>
-                <EngineFamily>{{ dbproxy.engine_family }}</EngineFamily>
-                <UpdatedDate>{{ dbproxy.updated_date }}</UpdatedDate>
-                <DBProxyName>{{ dbproxy.db_proxy_name }}</DBProxyName>
-                <IdleClientTimeout>{{ dbproxy.idle_client_timeout }}</IdleClientTimeout>
-                <Endpoint>{{ dbproxy.endpoint }}</Endpoint>
-                <CreatedDate>{{ dbproxy.created_date }}</CreatedDate>
-                <RoleArn>{{ dbproxy.role_arn }}</RoleArn>
-                <DebugLogging>{{ 'true' if dbproxy.debug_logging else 'false' }}</DebugLogging>
-                <VpcId>{{ dbproxy.vpc_id }}</VpcId>
-                <DBProxyArn>{{ dbproxy.arn }}</DBProxyArn>
-                <VpcSubnetIds>
-                  {% for vpcsubnetid in dbproxy.vpc_subnet_ids %}
-                    <member>{{ vpcsubnetid }}</member>
-                  {% endfor %}
-                </VpcSubnetIds>
-                <Status>{{ dbproxy.status }}</Status>
-        """
-        )
-        return template.render(dbproxy=self)
-
 
 class RDSBackend(BaseBackend):
     def __init__(self, region_name: str, account_id: str):
@@ -3221,34 +2673,6 @@ class OptionGroup(RDSBaseModel):
     def name(self) -> str:
         return self._name
 
-    def to_xml(self) -> str:
-        template = Template(
-            """<OptionGroup>
-          <OptionGroupName>{{ option_group.name }}</OptionGroupName>
-          <AllowsVpcAndNonVpcInstanceMemberships>{{ option_group.vpc_and_non_vpc_instance_memberships }}</AllowsVpcAndNonVpcInstanceMemberships>
-          <MajorEngineVersion>{{ option_group.major_engine_version }}</MajorEngineVersion>
-          <EngineName>{{ option_group.engine_name }}</EngineName>
-          <OptionGroupDescription>{{ option_group.description }}</OptionGroupDescription>
-          <OptionGroupArn>{{ option_group.arn }}</OptionGroupArn>
-          <Options>
-              {% for name, option_settings in option_group.options.items() %}
-              <Option>
-                <OptionName>{{ name }}</OptionName>
-                <OptionSettings>
-                  {% for setting in option_settings %}
-                  <OptionSetting>
-                    <Name>{{ setting.get("Name") }}</Name>
-                    <Value>{{ setting.get("Value") }}</Value>
-                  </OptionSetting>
-                  {% endfor %}
-                </OptionSettings>
-              </Option>
-              {% endfor %}
-          </Options>
-        </OptionGroup>"""
-        )
-        return template.render(option_group=self)
-
     def remove_options(self, options_to_remove: Any) -> None:
         for option in options_to_remove:
             if isinstance(option, str):
@@ -3284,17 +2708,6 @@ class DBParameterGroup(CloudFormationModel, RDSBaseModel):
     def name(self) -> str:
         return self._name
 
-    def to_xml(self) -> str:
-        template = Template(
-            """<DBParameterGroup>
-          <DBParameterGroupName>{{ param_group.name }}</DBParameterGroupName>
-          <DBParameterGroupFamily>{{ param_group.family }}</DBParameterGroupFamily>
-          <Description>{{ param_group.description }}</Description>
-          <DBParameterGroupArn>{{ param_group.arn }}</DBParameterGroupArn>
-        </DBParameterGroup>"""
-        )
-        return template.render(param_group=self)
-
     def update_parameters(self, new_parameters: Iterable[Dict[str, Any]]) -> None:
         for new_parameter in new_parameters:
             parameter = self.parameters[new_parameter["ParameterName"]]
@@ -3360,16 +2773,5 @@ class DBClusterParameterGroup(CloudFormationModel, RDSBaseModel):
     def name(self) -> str:
         return self._name
 
-    def to_xml(self) -> str:
-        template = Template(
-            """<DBClusterParameterGroup>
-          <DBClusterParameterGroupName>{{ param_group.name }}</DBClusterParameterGroupName>
-          <DBParameterGroupFamily>{{ param_group.family }}</DBParameterGroupFamily>
-          <Description>{{ param_group.description }}</Description>
-          <DBClusterParameterGroupArn>{{ param_group.arn }}</DBClusterParameterGroupArn>
-        </DBClusterParameterGroup>"""
-        )
-        return template.render(param_group=self)
-
 
 rds_backends = BackendDict(RDSBackend, "rds")
diff --git a/moto/rds/responses.py b/moto/rds/responses.py
index 85ef5081b..bf1c359ab 100644
--- a/moto/rds/responses.py
+++ b/moto/rds/responses.py
@@ -1,14 +1,49 @@
 from collections import defaultdict
 from typing import Any, Dict, Iterable, List, Optional, Tuple
 
+from botocore.awsrequest import AWSPreparedRequest
+from werkzeug.wrappers import Request
+
+from moto import settings
+from moto.core.common_types import TYPE_RESPONSE
 from moto.core.responses import BaseResponse
 from moto.ec2.models import ec2_backends
 
-from .exceptions import DBParameterGroupNotFoundError
+from .exceptions import DBParameterGroupNotFoundError, RDSClientError
 from .models import RDSBackend, rds_backends
+from .viewmodels import (
+    DBClusterDTO,
+    DBClusterSnapshotDTO,
+    DBInstanceDTO,
+    DBProxyTargetDTO,
+    DBProxyTargetGroupDTO,
+    DBSecurityGroupDTO,
+    DBSnapshotDTO,
+    DBSubnetGroupDTO,
+    GlobalClusterDTO,
+    OptionGroupDTO,
+)
+
+
+def normalize_request(request: AWSPreparedRequest) -> Request:
+    from urllib.parse import urlparse
+
+    parsed_url = urlparse(request.url)
+    normalized_request = Request.from_values(
+        method=request.method,
+        base_url=f"{parsed_url.scheme}://{parsed_url.netloc}",
+        path=parsed_url.path,
+        query_string=parsed_url.query,
+        data=request.body,
+        headers=[(k, v) for k, v in request.headers.items()],
+    )
+    return normalized_request
 
 
 class RDSResponse(BaseResponse):
+    def __init__(self) -> None:
+        super().__init__(service_name="rds")
+
     @property
     def backend(self) -> RDSBackend:
         return rds_backends[self.current_account][self.region]
@@ -18,6 +53,45 @@ class RDSResponse(BaseResponse):
         """Return backend instance of the region that stores Global Clusters"""
         return rds_backends[self.current_account]["us-east-1"]
 
+    def _dispatch(self, request: Any, full_url: str, headers: Any) -> TYPE_RESPONSE:
+        # return super()._dispatch(request, full_url, headers)
+        self.setup_class(request, full_url, headers)
+
+        if isinstance(request, AWSPreparedRequest):
+            request = normalize_request(request)
+
+        from .serialize import QuerySerializer
+        from .utils import ValuePicker, get_service_model
+        from .viewmodels import SERIALIZATION_ALIASES
+
+        self.action = request.values["Action"]
+
+        service_model = get_service_model(self.service_name)
+        self.operation_model = service_model.operation_model(self.action)
+
+        # parser = QueryParser()
+        # parsed = parser.get_parameters(
+        #     {"query_params": request.values}, self.operation_model
+        # )
+        # self.parameters = xform_dict(parsed)
+
+        value_picker = ValuePicker(SERIALIZATION_ALIASES)
+        self.serializer = QuerySerializer(
+            self.operation_model,
+            {"request-id": "request-id"},
+            value_picker=value_picker,
+            pretty_print=settings.PRETTIFY_RESPONSES,
+        )
+        try:
+            response = self.call_action()
+        except RDSClientError as e:
+            response = self.serialize(e)
+        return response
+
+    def serialize(self, result: Any) -> TYPE_RESPONSE:
+        serialized = self.serializer.serialize_to_response(result)
+        return serialized["status_code"], serialized["headers"], serialized["body"]
+
     def _get_db_kwargs(self) -> Dict[str, Any]:
         args = {
             "auto_minor_version_upgrade": self._get_param("AutoMinorVersionUpgrade"),
@@ -258,20 +332,19 @@ class RDSResponse(BaseResponse):
         root = self._get_multi_param_dict(label) or {}
         return root.get(child_label, [])
 
-    def create_db_instance(self) -> str:
+    def create_db_instance(self) -> TYPE_RESPONSE:
         db_kwargs = self._get_db_kwargs()
         database = self.backend.create_db_instance(db_kwargs)
-        template = self.response_template(CREATE_DATABASE_TEMPLATE)
-        return template.render(database=database)
+        result = {"DBInstance": DBInstanceDTO(database)}
+        return self.serialize(result)
 
-    def create_db_instance_read_replica(self) -> str:
+    def create_db_instance_read_replica(self) -> TYPE_RESPONSE:
         db_kwargs = self._get_db_replica_kwargs()
-
         database = self.backend.create_db_instance_read_replica(db_kwargs)
-        template = self.response_template(CREATE_DATABASE_REPLICA_TEMPLATE)
-        return template.render(database=database)
+        result = {"DBInstance": DBInstanceDTO(database)}
+        return self.serialize(result)
 
-    def describe_db_instances(self) -> str:
+    def describe_db_instances(self) -> TYPE_RESPONSE:
         db_instance_identifier = self._get_param("DBInstanceIdentifier")
         filters = self._get_multi_param("Filters.Filter.")
         filter_dict = {f["Name"]: f["Values"] for f in filters}
@@ -281,10 +354,13 @@ class RDSResponse(BaseResponse):
             )
         )
         instances_resp, next_marker = self._paginate(all_instances)
-        template = self.response_template(DESCRIBE_DATABASES_TEMPLATE)
-        return template.render(databases=instances_resp, marker=next_marker)
+        result = {
+            "DBInstances": [DBInstanceDTO(db) for db in instances_resp],
+            "Marker": next_marker,
+        }
+        return self.serialize(result)
 
-    def modify_db_instance(self) -> str:
+    def modify_db_instance(self) -> TYPE_RESPONSE:
         db_instance_identifier = self._get_param("DBInstanceIdentifier")
         db_kwargs = self._get_db_kwargs()
         # NOTE modify_db_instance does not support tags
@@ -293,10 +369,10 @@ class RDSResponse(BaseResponse):
         if new_db_instance_identifier:
             db_kwargs["new_db_instance_identifier"] = new_db_instance_identifier
         database = self.backend.modify_db_instance(db_instance_identifier, db_kwargs)
-        template = self.response_template(MODIFY_DATABASE_TEMPLATE)
-        return template.render(database=database)
+        result = {"DBInstance": DBInstanceDTO(database)}
+        return self.serialize(result)
 
-    def delete_db_instance(self) -> str:
+    def delete_db_instance(self) -> TYPE_RESPONSE:
         db_instance_identifier = self._get_param("DBInstanceIdentifier")
         db_snapshot_name = self._get_param("FinalDBSnapshotIdentifier")
         if db_snapshot_name is not None:
@@ -307,16 +383,16 @@ class RDSResponse(BaseResponse):
         database = self.backend.delete_db_instance(
             db_instance_identifier, db_snapshot_name
         )
-        template = self.response_template(DELETE_DATABASE_TEMPLATE)
-        return template.render(database=database)
+        result = {"DBInstance": DBInstanceDTO(database)}
+        return self.serialize(result)
 
-    def reboot_db_instance(self) -> str:
+    def reboot_db_instance(self) -> TYPE_RESPONSE:
         db_instance_identifier = self._get_param("DBInstanceIdentifier")
         database = self.backend.reboot_db_instance(db_instance_identifier)
-        template = self.response_template(REBOOT_DATABASE_TEMPLATE)
-        return template.render(database=database)
+        result = {"DBInstance": DBInstanceDTO(database)}
+        return self.serialize(result)
 
-    def create_db_snapshot(self) -> str:
+    def create_db_snapshot(self) -> TYPE_RESPONSE:
         db_instance_identifier = self._get_param("DBInstanceIdentifier")
         db_snapshot_identifier = self._get_param("DBSnapshotIdentifier")
         tags = self.unpack_list_params("Tags", "Tag")
@@ -328,10 +404,10 @@ class RDSResponse(BaseResponse):
             db_snapshot_identifier,
             tags=tags,
         )
-        template = self.response_template(CREATE_SNAPSHOT_TEMPLATE)
-        return template.render(snapshot=snapshot)
+        result = {"DBSnapshot": DBSnapshotDTO(snapshot)}
+        return self.serialize(result)
 
-    def copy_db_snapshot(self) -> str:
+    def copy_db_snapshot(self) -> TYPE_RESPONSE:
         source_snapshot_identifier = self._get_param("SourceDBSnapshotIdentifier")
         target_snapshot_identifier = self._get_param("TargetDBSnapshotIdentifier")
         tags = self.unpack_list_params("Tags", "Tag")
@@ -343,10 +419,10 @@ class RDSResponse(BaseResponse):
         snapshot = self.backend.copy_db_snapshot(
             source_snapshot_identifier, target_snapshot_identifier, tags, copy_tags
         )
-        template = self.response_template(COPY_SNAPSHOT_TEMPLATE)
-        return template.render(snapshot=snapshot)
+        result = {"DBSnapshot": DBSnapshotDTO(snapshot)}
+        return self.serialize(result)
 
-    def describe_db_snapshots(self) -> str:
+    def describe_db_snapshots(self) -> TYPE_RESPONSE:
         db_instance_identifier = self._get_param("DBInstanceIdentifier")
         db_snapshot_identifier = self._get_param("DBSnapshotIdentifier")
         filters = self._get_multi_param("Filters.Filter.")
@@ -354,33 +430,33 @@ class RDSResponse(BaseResponse):
         snapshots = self.backend.describe_db_snapshots(
             db_instance_identifier, db_snapshot_identifier, filter_dict
         )
-        template = self.response_template(DESCRIBE_SNAPSHOTS_TEMPLATE)
-        return template.render(snapshots=snapshots)
+        result = {"DBSnapshots": [DBSnapshotDTO(snapshot) for snapshot in snapshots]}
+        return self.serialize(result)
 
-    def promote_read_replica(self) -> str:
+    def promote_read_replica(self) -> TYPE_RESPONSE:
         db_instance_identifier = self._get_param("DBInstanceIdentifier")
         db_kwargs = self._get_db_kwargs()
         database = self.backend.promote_read_replica(db_kwargs)
         database = self.backend.modify_db_instance(db_instance_identifier, db_kwargs)
-        template = self.response_template(PROMOTE_REPLICA_TEMPLATE)
-        return template.render(database=database)
+        result = {"DBInstance": DBInstanceDTO(database)}
+        return self.serialize(result)
 
-    def delete_db_snapshot(self) -> str:
+    def delete_db_snapshot(self) -> TYPE_RESPONSE:
         db_snapshot_identifier = self._get_param("DBSnapshotIdentifier")
         snapshot = self.backend.delete_db_snapshot(db_snapshot_identifier)
-        template = self.response_template(DELETE_SNAPSHOT_TEMPLATE)
-        return template.render(snapshot=snapshot)
+        result = {"DBSnapshot": DBSnapshotDTO(snapshot)}
+        return self.serialize(result)
 
-    def restore_db_instance_from_db_snapshot(self) -> str:
+    def restore_db_instance_from_db_snapshot(self) -> TYPE_RESPONSE:
         db_snapshot_identifier = self._get_param("DBSnapshotIdentifier")
         db_kwargs = self._get_db_kwargs()
         new_instance = self.backend.restore_db_instance_from_db_snapshot(
             db_snapshot_identifier, db_kwargs
         )
-        template = self.response_template(RESTORE_INSTANCE_FROM_SNAPSHOT_TEMPLATE)
-        return template.render(database=new_instance)
+        result = {"DBInstance": DBInstanceDTO(new_instance)}
+        return self.serialize(result)
 
-    def restore_db_instance_to_point_in_time(self) -> str:
+    def restore_db_instance_to_point_in_time(self) -> TYPE_RESPONSE:
         source_db_identifier = self._get_param("SourceDBInstanceIdentifier")
         target_db_identifier = self._get_param("TargetDBInstanceIdentifier")
 
@@ -388,30 +464,28 @@ class RDSResponse(BaseResponse):
         new_instance = self.backend.restore_db_instance_to_point_in_time(
             source_db_identifier, target_db_identifier, db_kwargs
         )
-        template = self.response_template(RESTORE_INSTANCE_TO_POINT_IN_TIME_TEMPLATE)
-        return template.render(database=new_instance)
+        result = {"DBInstance": DBInstanceDTO(new_instance)}
+        return self.serialize(result)
 
-    def list_tags_for_resource(self) -> str:
+    def list_tags_for_resource(self) -> TYPE_RESPONSE:
         arn = self._get_param("ResourceName")
-        template = self.response_template(LIST_TAGS_FOR_RESOURCE_TEMPLATE)
         tags = self.backend.list_tags_for_resource(arn)
-        return template.render(tags=tags)
+        result = {"TagList": tags}
+        return self.serialize(result)
 
-    def add_tags_to_resource(self) -> str:
+    def add_tags_to_resource(self) -> TYPE_RESPONSE:
         arn = self._get_param("ResourceName")
         tags = self.unpack_list_params("Tags", "Tag")
-        tags = self.backend.add_tags_to_resource(arn, tags)
-        template = self.response_template(ADD_TAGS_TO_RESOURCE_TEMPLATE)
-        return template.render(tags=tags)
+        self.backend.add_tags_to_resource(arn, tags)
+        return self.serialize({})
 
-    def remove_tags_from_resource(self) -> str:
+    def remove_tags_from_resource(self) -> TYPE_RESPONSE:
         arn = self._get_param("ResourceName")
         tag_keys = self.unpack_list_params("TagKeys", "member")
         self.backend.remove_tags_from_resource(arn, tag_keys)  # type: ignore
-        template = self.response_template(REMOVE_TAGS_FROM_RESOURCE_TEMPLATE)
-        return template.render()
+        return self.serialize({})
 
-    def stop_db_instance(self) -> str:
+    def stop_db_instance(self) -> TYPE_RESPONSE:
         db_instance_identifier = self._get_param("DBInstanceIdentifier")
         db_snapshot_identifier = self._get_param("DBSnapshotIdentifier")
         if db_snapshot_identifier is not None:
@@ -422,47 +496,49 @@ class RDSResponse(BaseResponse):
         database = self.backend.stop_db_instance(
             db_instance_identifier, db_snapshot_identifier
         )
-        template = self.response_template(STOP_DATABASE_TEMPLATE)
-        return template.render(database=database)
+        result = {"DBInstance": database}
+        return self.serialize(result)
 
-    def start_db_instance(self) -> str:
+    def start_db_instance(self) -> TYPE_RESPONSE:
         db_instance_identifier = self._get_param("DBInstanceIdentifier")
         database = self.backend.start_db_instance(db_instance_identifier)
-        template = self.response_template(START_DATABASE_TEMPLATE)
-        return template.render(database=database)
+        result = {"DBInstance": database}
+        return self.serialize(result)
 
-    def create_db_security_group(self) -> str:
+    def create_db_security_group(self) -> TYPE_RESPONSE:
         group_name = self._get_param("DBSecurityGroupName")
         description = self._get_param("DBSecurityGroupDescription")
         tags = self.unpack_list_params("Tags", "Tag")
         security_group = self.backend.create_db_security_group(
             group_name, description, tags
         )
-        template = self.response_template(CREATE_SECURITY_GROUP_TEMPLATE)
-        return template.render(security_group=security_group)
+        result = {"DBSecurityGroup": DBSecurityGroupDTO(security_group)}
+        return self.serialize(result)
 
-    def describe_db_security_groups(self) -> str:
+    def describe_db_security_groups(self) -> TYPE_RESPONSE:
         security_group_name = self._get_param("DBSecurityGroupName")
         security_groups = self.backend.describe_security_groups(security_group_name)
-        template = self.response_template(DESCRIBE_SECURITY_GROUPS_TEMPLATE)
-        return template.render(security_groups=security_groups)
+        result = {
+            "DBSecurityGroups": [DBSecurityGroupDTO(sg) for sg in security_groups]
+        }
+        return self.serialize(result)
 
-    def delete_db_security_group(self) -> str:
+    def delete_db_security_group(self) -> TYPE_RESPONSE:
         security_group_name = self._get_param("DBSecurityGroupName")
         security_group = self.backend.delete_security_group(security_group_name)
-        template = self.response_template(DELETE_SECURITY_GROUP_TEMPLATE)
-        return template.render(security_group=security_group)
+        result = {"DBSecurityGroup": DBSecurityGroupDTO(security_group)}
+        return self.serialize(result)
 
-    def authorize_db_security_group_ingress(self) -> str:
+    def authorize_db_security_group_ingress(self) -> TYPE_RESPONSE:
         security_group_name = self._get_param("DBSecurityGroupName")
         cidr_ip = self._get_param("CIDRIP")
         security_group = self.backend.authorize_security_group(
             security_group_name, cidr_ip
         )
-        template = self.response_template(AUTHORIZE_SECURITY_GROUP_TEMPLATE)
-        return template.render(security_group=security_group)
+        result = {"DBSecurityGroup": DBSecurityGroupDTO(security_group)}
+        return self.serialize(result)
 
-    def create_db_subnet_group(self) -> str:
+    def create_db_subnet_group(self) -> TYPE_RESPONSE:
         subnet_name = self._get_param("DBSubnetGroupName")
         description = self._get_param("DBSubnetGroupDescription")
         subnet_ids = self._get_multi_param("SubnetIds.SubnetIdentifier")
@@ -474,16 +550,18 @@ class RDSResponse(BaseResponse):
         subnet_group = self.backend.create_subnet_group(
             subnet_name, description, subnets, tags
         )
-        template = self.response_template(CREATE_SUBNET_GROUP_TEMPLATE)
-        return template.render(subnet_group=subnet_group)
+        result = {"DBSubnetGroup": DBSubnetGroupDTO(subnet_group)}
+        return self.serialize(result)
 
-    def describe_db_subnet_groups(self) -> str:
+    def describe_db_subnet_groups(self) -> TYPE_RESPONSE:
         subnet_name = self._get_param("DBSubnetGroupName")
         subnet_groups = self.backend.describe_db_subnet_groups(subnet_name)
-        template = self.response_template(DESCRIBE_SUBNET_GROUPS_TEMPLATE)
-        return template.render(subnet_groups=subnet_groups)
+        result = {
+            "DBSubnetGroups": [DBSubnetGroupDTO(group) for group in subnet_groups]
+        }
+        return self.serialize(result)
 
-    def modify_db_subnet_group(self) -> str:
+    def modify_db_subnet_group(self) -> TYPE_RESPONSE:
         subnet_name = self._get_param("DBSubnetGroupName")
         description = self._get_param("DBSubnetGroupDescription")
         subnet_ids = self._get_multi_param("SubnetIds.SubnetIdentifier")
@@ -494,33 +572,36 @@ class RDSResponse(BaseResponse):
         subnet_group = self.backend.modify_db_subnet_group(
             subnet_name, description, subnets
         )
-        template = self.response_template(MODIFY_SUBNET_GROUPS_TEMPLATE)
-        return template.render(subnet_group=subnet_group)
+        result = {"DBSubnetGroup": DBSubnetGroupDTO(subnet_group)}
+        return self.serialize(result)
 
-    def delete_db_subnet_group(self) -> str:
+    def delete_db_subnet_group(self) -> TYPE_RESPONSE:
         subnet_name = self._get_param("DBSubnetGroupName")
         subnet_group = self.backend.delete_subnet_group(subnet_name)
-        template = self.response_template(DELETE_SUBNET_GROUP_TEMPLATE)
-        return template.render(subnet_group=subnet_group)
+        result = {"DBSubnetGroup": DBSubnetGroupDTO(subnet_group)}
+        return self.serialize(result)
 
-    def create_option_group(self) -> str:
+    def create_option_group(self) -> TYPE_RESPONSE:
         kwargs = self._get_option_group_kwargs()
         option_group = self.backend.create_option_group(kwargs)
-        template = self.response_template(CREATE_OPTION_GROUP_TEMPLATE)
-        return template.render(option_group=option_group)
+        result = {"OptionGroup": OptionGroupDTO(option_group)}
+        return self.serialize(result)
 
-    def delete_option_group(self) -> str:
+    def delete_option_group(self) -> TYPE_RESPONSE:
         kwargs = self._get_option_group_kwargs()
         option_group = self.backend.delete_option_group(kwargs["name"])
-        template = self.response_template(DELETE_OPTION_GROUP_TEMPLATE)
-        return template.render(option_group=option_group)
+        result = {"OptionGroup": OptionGroupDTO(option_group)}
+        return self.serialize(result)
 
-    def describe_option_groups(self) -> str:
+    def describe_option_groups(self) -> TYPE_RESPONSE:
         kwargs = self._get_option_group_kwargs()
         option_groups = self.backend.describe_option_groups(kwargs)
-        option_groups, _ = self._paginate(option_groups)
-        template = self.response_template(DESCRIBE_OPTION_GROUP_TEMPLATE)
-        return template.render(option_groups=option_groups)
+        option_groups, marker = self._paginate(option_groups)
+        result = {
+            "OptionGroupsList": [OptionGroupDTO(group) for group in option_groups],
+            "Marker": marker,
+        }
+        return self.serialize(result)
 
     def describe_option_group_options(self) -> str:
         engine_name = self._get_param("EngineName")
@@ -529,7 +610,7 @@ class RDSResponse(BaseResponse):
             engine_name, major_engine_version
         )
 
-    def modify_option_group(self) -> str:
+    def modify_option_group(self) -> TYPE_RESPONSE:
         option_group_name = self._get_param("OptionGroupName")
         options_to_include = (self._get_multi_param_dict("OptionsToInclude") or {}).get(
             "OptionConfiguration", []
@@ -539,30 +620,30 @@ class RDSResponse(BaseResponse):
         option_group = self.backend.modify_option_group(
             option_group_name, options_to_include, options_to_remove
         )
-        template = self.response_template(MODIFY_OPTION_GROUP_TEMPLATE)
-        return template.render(option_group=option_group)
+        result = {"OptionGroup": OptionGroupDTO(option_group)}
+        return self.serialize(result)
 
-    def create_db_parameter_group(self) -> str:
+    def create_db_parameter_group(self) -> TYPE_RESPONSE:
         kwargs = self._get_db_parameter_group_kwargs()
         db_parameter_group = self.backend.create_db_parameter_group(kwargs)
-        template = self.response_template(CREATE_DB_PARAMETER_GROUP_TEMPLATE)
-        return template.render(db_parameter_group=db_parameter_group)
+        result = {"DBParameterGroup": db_parameter_group}
+        return self.serialize(result)
 
-    def describe_db_parameter_groups(self) -> str:
+    def describe_db_parameter_groups(self) -> TYPE_RESPONSE:
         kwargs = self._get_db_parameter_group_kwargs()
         db_parameter_groups = self.backend.describe_db_parameter_groups(kwargs)
         db_parameter_groups, _ = self._paginate(db_parameter_groups)
-        template = self.response_template(DESCRIBE_DB_PARAMETER_GROUPS_TEMPLATE)
-        return template.render(db_parameter_groups=db_parameter_groups)
+        result = {"DBParameterGroups": db_parameter_groups}
+        return self.serialize(result)
 
-    def modify_db_parameter_group(self) -> str:
+    def modify_db_parameter_group(self) -> TYPE_RESPONSE:
         db_parameter_group_name = self._get_param("DBParameterGroupName")
         db_parameter_group_parameters = self._get_db_parameter_group_parameters()
         db_parameter_group = self.backend.modify_db_parameter_group(
             db_parameter_group_name, db_parameter_group_parameters
         )
-        template = self.response_template(MODIFY_DB_PARAMETER_GROUP_TEMPLATE)
-        return template.render(db_parameter_group=db_parameter_group)
+        result = {"DBParameterGroupName": db_parameter_group.name}
+        return self.serialize(result)
 
     def _get_db_parameter_group_parameters(self) -> Iterable[Dict[str, Any]]:
         parameter_group_parameters: Dict[str, Any] = defaultdict(dict)
@@ -578,86 +659,85 @@ class RDSResponse(BaseResponse):
 
         return parameter_group_parameters.values()
 
-    def describe_db_parameters(self) -> str:
+    def describe_db_parameters(self) -> TYPE_RESPONSE:
         db_parameter_group_name = self._get_param("DBParameterGroupName")
         db_parameter_groups = self.backend.describe_db_parameter_groups(
             {"name": db_parameter_group_name}
         )
         if not db_parameter_groups:
             raise DBParameterGroupNotFoundError(db_parameter_group_name)
+        parameters = db_parameter_groups[0].parameters.values()
+        result = {"Parameters": parameters}
+        return self.serialize(result)
 
-        template = self.response_template(DESCRIBE_DB_PARAMETERS_TEMPLATE)
-        return template.render(db_parameter_group=db_parameter_groups[0])
-
-    def delete_db_parameter_group(self) -> str:
+    def delete_db_parameter_group(self) -> TYPE_RESPONSE:
         kwargs = self._get_db_parameter_group_kwargs()
         db_parameter_group = self.backend.delete_db_parameter_group(kwargs["name"])
-        template = self.response_template(DELETE_DB_PARAMETER_GROUP_TEMPLATE)
-        return template.render(db_parameter_group=db_parameter_group)
+        return self.serialize(db_parameter_group)
 
-    def describe_db_cluster_parameters(self) -> str:
+    def describe_db_cluster_parameters(self) -> TYPE_RESPONSE:
+        # TODO: This never worked at all...
         db_parameter_group_name = self._get_param("DBParameterGroupName")
         db_parameter_groups = self.backend.describe_db_cluster_parameters()
         if db_parameter_groups is None:
             raise DBParameterGroupNotFoundError(db_parameter_group_name)
+        result = {"Parameters": db_parameter_groups}
+        return self.serialize(result)
 
-        template = self.response_template(DESCRIBE_DB_CLUSTER_PARAMETERS_TEMPLATE)
-        return template.render(db_parameter_group=db_parameter_groups)
-
-    def create_db_cluster(self) -> str:
+    def create_db_cluster(self) -> TYPE_RESPONSE:
         kwargs = self._get_db_cluster_kwargs()
         cluster = self.backend.create_db_cluster(kwargs)
-        template = self.response_template(CREATE_DB_CLUSTER_TEMPLATE)
-        return template.render(cluster=cluster)
+        result = {"DBCluster": DBClusterDTO(cluster, creating=True)}
+        return self.serialize(result)
 
-    def modify_db_cluster(self) -> str:
+    def modify_db_cluster(self) -> TYPE_RESPONSE:
         kwargs = self._get_modify_db_cluster_kwargs()
         cluster = self.backend.modify_db_cluster(kwargs)
-        template = self.response_template(MODIFY_DB_CLUSTER_TEMPLATE)
-        return template.render(cluster=cluster)
+        result = {"DBCluster": DBClusterDTO(cluster)}
+        return self.serialize(result)
 
-    def describe_db_clusters(self) -> str:
+    def describe_db_clusters(self) -> TYPE_RESPONSE:
         _id = self._get_param("DBClusterIdentifier")
         filters = self._get_multi_param("Filters.Filter.")
         filter_dict = {f["Name"]: f["Values"] for f in filters}
         clusters = self.backend.describe_db_clusters(
             cluster_identifier=_id, filters=filter_dict
         )
-        template = self.response_template(DESCRIBE_CLUSTERS_TEMPLATE)
-        return template.render(clusters=clusters)
+        result = {"DBClusters": [DBClusterDTO(cluster) for cluster in clusters]}
+        return self.serialize(result)
 
-    def delete_db_cluster(self) -> str:
+    def delete_db_cluster(self) -> TYPE_RESPONSE:
         _id = self._get_param("DBClusterIdentifier")
         snapshot_name = self._get_param("FinalDBSnapshotIdentifier")
         cluster = self.backend.delete_db_cluster(
             cluster_identifier=_id, snapshot_name=snapshot_name
         )
-        template = self.response_template(DELETE_CLUSTER_TEMPLATE)
-        return template.render(cluster=cluster)
+        result = {"DBCluster": DBClusterDTO(cluster)}
+        return self.serialize(result)
 
-    def start_db_cluster(self) -> str:
+    def start_db_cluster(self) -> TYPE_RESPONSE:
         _id = self._get_param("DBClusterIdentifier")
         cluster = self.backend.start_db_cluster(cluster_identifier=_id)
-        template = self.response_template(START_CLUSTER_TEMPLATE)
-        return template.render(cluster=cluster)
+        result = {"DBCluster": DBClusterDTO(cluster)}
+        return self.serialize(result)
 
-    def stop_db_cluster(self) -> str:
+    def stop_db_cluster(self) -> TYPE_RESPONSE:
         _id = self._get_param("DBClusterIdentifier")
         cluster = self.backend.stop_db_cluster(cluster_identifier=_id)
-        template = self.response_template(STOP_CLUSTER_TEMPLATE)
-        return template.render(cluster=cluster)
+        result = {"DBCluster": DBClusterDTO(cluster)}
+        return self.serialize(result)
 
-    def create_db_cluster_snapshot(self) -> str:
+    def create_db_cluster_snapshot(self) -> TYPE_RESPONSE:
         db_cluster_identifier = self._get_param("DBClusterIdentifier")
         db_snapshot_identifier = self._get_param("DBClusterSnapshotIdentifier")
         tags = self.unpack_list_params("Tags", "Tag")
         snapshot = self.backend.create_db_cluster_snapshot(
             db_cluster_identifier, db_snapshot_identifier, tags=tags
         )
-        template = self.response_template(CREATE_CLUSTER_SNAPSHOT_TEMPLATE)
-        return template.render(snapshot=snapshot)
+        result = {"DBClusterSnapshot": DBClusterSnapshotDTO(snapshot)}
+        return self.serialize(result)
 
-    def copy_db_cluster_snapshot(self) -> str:
+    def copy_db_cluster_snapshot(self) -> TYPE_RESPONSE:
         source_snapshot_identifier = self._get_param(
             "SourceDBClusterSnapshotIdentifier"
         )
@@ -668,10 +748,10 @@ class RDSResponse(BaseResponse):
         snapshot = self.backend.copy_db_cluster_snapshot(
             source_snapshot_identifier, target_snapshot_identifier, tags
         )
-        template = self.response_template(COPY_CLUSTER_SNAPSHOT_TEMPLATE)
-        return template.render(snapshot=snapshot)
+        result = {"DBClusterSnapshot": DBClusterSnapshotDTO(snapshot)}
+        return self.serialize(result)
 
-    def describe_db_cluster_snapshots(self) -> str:
+    def describe_db_cluster_snapshots(self) -> TYPE_RESPONSE:
         db_cluster_identifier = self._get_param("DBClusterIdentifier")
         db_snapshot_identifier = self._get_param("DBClusterSnapshotIdentifier")
         filters = self._get_multi_param("Filters.Filter.")
@@ -679,75 +759,77 @@ class RDSResponse(BaseResponse):
         snapshots = self.backend.describe_db_cluster_snapshots(
             db_cluster_identifier, db_snapshot_identifier, filter_dict
         )
-        template = self.response_template(DESCRIBE_CLUSTER_SNAPSHOTS_TEMPLATE)
-        return template.render(snapshots=snapshots)
+        results = {
+            "DBClusterSnapshots": [
+                DBClusterSnapshotDTO(snapshot) for snapshot in snapshots
+            ]
+        }
+        return self.serialize(results)
 
-    def delete_db_cluster_snapshot(self) -> str:
+    def delete_db_cluster_snapshot(self) -> TYPE_RESPONSE:
         db_snapshot_identifier = self._get_param("DBClusterSnapshotIdentifier")
         snapshot = self.backend.delete_db_cluster_snapshot(db_snapshot_identifier)
-        template = self.response_template(DELETE_CLUSTER_SNAPSHOT_TEMPLATE)
-        return template.render(snapshot=snapshot)
+        result = {"DBClusterSnapshot": DBClusterSnapshotDTO(snapshot)}
+        return self.serialize(result)
 
-    def restore_db_cluster_from_snapshot(self) -> str:
+    def restore_db_cluster_from_snapshot(self) -> TYPE_RESPONSE:
         db_snapshot_identifier = self._get_param("SnapshotIdentifier")
         db_kwargs = self._get_db_cluster_kwargs()
         new_cluster = self.backend.restore_db_cluster_from_snapshot(
             db_snapshot_identifier, db_kwargs
         )
-        template = self.response_template(RESTORE_CLUSTER_FROM_SNAPSHOT_TEMPLATE)
-        return template.render(cluster=new_cluster)
+        result = {"DBCluster": DBClusterDTO(new_cluster)}
+        return self.serialize(result)
 
-    def start_export_task(self) -> str:
+    def start_export_task(self) -> TYPE_RESPONSE:
         kwargs = self._get_export_task_kwargs()
         export_task = self.backend.start_export_task(kwargs)
-        template = self.response_template(START_EXPORT_TASK_TEMPLATE)
-        return template.render(task=export_task)
+        return self.serialize(export_task)
 
-    def cancel_export_task(self) -> str:
+    def cancel_export_task(self) -> TYPE_RESPONSE:
         export_task_identifier = self._get_param("ExportTaskIdentifier")
         export_task = self.backend.cancel_export_task(export_task_identifier)
-        template = self.response_template(CANCEL_EXPORT_TASK_TEMPLATE)
-        return template.render(task=export_task)
+        return self.serialize(export_task)
 
-    def describe_export_tasks(self) -> str:
+    def describe_export_tasks(self) -> TYPE_RESPONSE:
         export_task_identifier = self._get_param("ExportTaskIdentifier")
         tasks = self.backend.describe_export_tasks(export_task_identifier)
-        template = self.response_template(DESCRIBE_EXPORT_TASKS_TEMPLATE)
-        return template.render(tasks=tasks)
+        result = {"ExportTasks": tasks}
+        return self.serialize(result)
 
-    def create_event_subscription(self) -> str:
+    def create_event_subscription(self) -> TYPE_RESPONSE:
         kwargs = self._get_event_subscription_kwargs()
         subscription = self.backend.create_event_subscription(kwargs)
-        template = self.response_template(CREATE_EVENT_SUBSCRIPTION_TEMPLATE)
-        return template.render(subscription=subscription)
+        result = {"EventSubscription": subscription}
+        return self.serialize(result)
 
-    def delete_event_subscription(self) -> str:
+    def delete_event_subscription(self) -> TYPE_RESPONSE:
         subscription_name = self._get_param("SubscriptionName")
         subscription = self.backend.delete_event_subscription(subscription_name)
-        template = self.response_template(DELETE_EVENT_SUBSCRIPTION_TEMPLATE)
-        return template.render(subscription=subscription)
+        result = {"EventSubscription": subscription}
+        return self.serialize(result)
 
-    def describe_event_subscriptions(self) -> str:
+    def describe_event_subscriptions(self) -> TYPE_RESPONSE:
         subscription_name = self._get_param("SubscriptionName")
         subscriptions = self.backend.describe_event_subscriptions(subscription_name)
-        template = self.response_template(DESCRIBE_EVENT_SUBSCRIPTIONS_TEMPLATE)
-        return template.render(subscriptions=subscriptions)
+        result = {"EventSubscriptionsList": subscriptions}
+        return self.serialize(result)
 
-    def describe_orderable_db_instance_options(self) -> str:
+    def describe_orderable_db_instance_options(self) -> TYPE_RESPONSE:
         engine = self._get_param("Engine")
         engine_version = self._get_param("EngineVersion")
         options = self.backend.describe_orderable_db_instance_options(
             engine, engine_version
         )
-        template = self.response_template(DESCRIBE_ORDERABLE_CLUSTER_OPTIONS)
-        return template.render(options=options, marker=None)
+        result = {"OrderableDBInstanceOptions": options}
+        return self.serialize(result)
 
-    def describe_global_clusters(self) -> str:
+    def describe_global_clusters(self) -> TYPE_RESPONSE:
         clusters = self.global_backend.describe_global_clusters()
-        template = self.response_template(DESCRIBE_GLOBAL_CLUSTERS_TEMPLATE)
-        return template.render(clusters=clusters)
+        result = {"GlobalClusters": [GlobalClusterDTO(cluster) for cluster in clusters]}
+        return self.serialize(result)
 
-    def create_global_cluster(self) -> str:
+    def create_global_cluster(self) -> TYPE_RESPONSE:
         params = self._get_params()
         cluster = self.global_backend.create_global_cluster(
             global_cluster_identifier=params["GlobalClusterIdentifier"],
@@ -757,27 +839,31 @@ class RDSResponse(BaseResponse):
             storage_encrypted=params.get("StorageEncrypted"),
             deletion_protection=params.get("DeletionProtection"),
         )
-        template = self.response_template(CREATE_GLOBAL_CLUSTER_TEMPLATE)
-        return template.render(cluster=cluster)
+        result = {"GlobalCluster": GlobalClusterDTO(cluster)}
+        return self.serialize(result)
 
-    def delete_global_cluster(self) -> str:
+    def delete_global_cluster(self) -> TYPE_RESPONSE:
         params = self._get_params()
         cluster = self.global_backend.delete_global_cluster(
             global_cluster_identifier=params["GlobalClusterIdentifier"],
         )
-        template = self.response_template(DELETE_GLOBAL_CLUSTER_TEMPLATE)
-        return template.render(cluster=cluster)
+        result = {"GlobalCluster": GlobalClusterDTO(cluster)}
+        return self.serialize(result)
 
-    def remove_from_global_cluster(self) -> str:
+    def remove_from_global_cluster(self) -> TYPE_RESPONSE:
         params = self._get_params()
         global_cluster = self.backend.remove_from_global_cluster(
             global_cluster_identifier=params["GlobalClusterIdentifier"],
             db_cluster_identifier=params["DbClusterIdentifier"],
         )
-        template = self.response_template(REMOVE_FROM_GLOBAL_CLUSTER_TEMPLATE)
-        return template.render(cluster=global_cluster)
+        result = {
+            "GlobalCluster": GlobalClusterDTO(global_cluster)
+            if global_cluster
+            else global_cluster
+        }
+        return self.serialize(result)
 
-    def create_db_cluster_parameter_group(self) -> str:
+    def create_db_cluster_parameter_group(self) -> TYPE_RESPONSE:
         group_name = self._get_param("DBClusterParameterGroupName")
         family = self._get_param("DBParameterGroupFamily")
         desc = self._get_param("Description")
@@ -786,44 +872,45 @@ class RDSResponse(BaseResponse):
             family=family,
             description=desc,
         )
-        template = self.response_template(CREATE_DB_CLUSTER_PARAMETER_GROUP_TEMPLATE)
-        return template.render(db_cluster_parameter_group=db_cluster_parameter_group)
+        result = {"DBClusterParameterGroup": db_cluster_parameter_group}
+        return self.serialize(result)
 
-    def describe_db_cluster_parameter_groups(self) -> str:
+    def describe_db_cluster_parameter_groups(self) -> TYPE_RESPONSE:
         group_name = self._get_param("DBClusterParameterGroupName")
         db_parameter_groups = self.backend.describe_db_cluster_parameter_groups(
             group_name=group_name,
         )
-        template = self.response_template(DESCRIBE_DB_CLUSTER_PARAMETER_GROUPS_TEMPLATE)
-        return template.render(db_parameter_groups=db_parameter_groups)
+        result = {"DBClusterParameterGroups": db_parameter_groups}
+        return self.serialize(result)
 
-    def delete_db_cluster_parameter_group(self) -> str:
+    def delete_db_cluster_parameter_group(self) -> TYPE_RESPONSE:
         group_name = self._get_param("DBClusterParameterGroupName")
         self.backend.delete_db_cluster_parameter_group(
             group_name=group_name,
         )
-        template = self.response_template(DELETE_DB_CLUSTER_PARAMETER_GROUP_TEMPLATE)
-        return template.render()
+        return self.serialize({})
 
-    def promote_read_replica_db_cluster(self) -> str:
+    def promote_read_replica_db_cluster(self) -> TYPE_RESPONSE:
         db_cluster_identifier = self._get_param("DBClusterIdentifier")
         cluster = self.backend.promote_read_replica_db_cluster(db_cluster_identifier)
-        template = self.response_template(PROMOTE_READ_REPLICA_DB_CLUSTER_TEMPLATE)
-        return template.render(cluster=cluster)
+        result = {"DBCluster": DBClusterDTO(cluster)}
+        return self.serialize(result)
 
-    def describe_db_snapshot_attributes(self) -> str:
+    def describe_db_snapshot_attributes(self) -> TYPE_RESPONSE:
         params = self._get_params()
         db_snapshot_identifier = params["DBSnapshotIdentifier"]
         db_snapshot_attributes_result = self.backend.describe_db_snapshot_attributes(
             db_snapshot_identifier=db_snapshot_identifier,
         )
-        template = self.response_template(DESCRIBE_DB_SNAPSHOT_ATTRIBUTES_TEMPLATE)
-        return template.render(
-            db_snapshot_attributes_result=db_snapshot_attributes_result,
-            db_snapshot_identifier=db_snapshot_identifier,
-        )
+        result = {
+            "DBSnapshotAttributesResult": {
+                "DBSnapshotIdentifier": db_snapshot_identifier,
+                "DBSnapshotAttributes": db_snapshot_attributes_result,
+            }
+        }
+        return self.serialize(result)
 
-    def modify_db_snapshot_attribute(self) -> str:
+    def modify_db_snapshot_attribute(self) -> TYPE_RESPONSE:
         params = self._get_params()
         db_snapshot_identifier = params["DBSnapshotIdentifier"]
         db_snapshot_attributes_result = self.backend.modify_db_snapshot_attribute(
@@ -832,13 +919,15 @@ class RDSResponse(BaseResponse):
             values_to_add=params.get("ValuesToAdd"),
             values_to_remove=params.get("ValuesToRemove"),
         )
-        template = self.response_template(MODIFY_DB_SNAPSHOT_ATTRIBUTE_TEMPLATE)
-        return template.render(
-            db_snapshot_attributes_result=db_snapshot_attributes_result,
-            db_snapshot_identifier=db_snapshot_identifier,
-        )
+        result = {
+            "DBSnapshotAttributesResult": {
+                "DBSnapshotIdentifier": db_snapshot_identifier,
+                "DBSnapshotAttributes": db_snapshot_attributes_result,
+            }
+        }
+        return self.serialize(result)
 
-    def describe_db_cluster_snapshot_attributes(self) -> str:
+    def describe_db_cluster_snapshot_attributes(self) -> TYPE_RESPONSE:
         params = self._get_params()
         db_cluster_snapshot_identifier = params["DBClusterSnapshotIdentifier"]
         db_cluster_snapshot_attributes_result = (
@@ -846,15 +935,15 @@ class RDSResponse(BaseResponse):
                 db_cluster_snapshot_identifier=db_cluster_snapshot_identifier,
             )
         )
-        template = self.response_template(
-            DESCRIBE_DB_CLUSTER_SNAPSHOT_ATTRIBUTES_TEMPLATE
-        )
-        return template.render(
-            db_cluster_snapshot_attributes_result=db_cluster_snapshot_attributes_result,
-            db_cluster_snapshot_identifier=db_cluster_snapshot_identifier,
-        )
+        result = {
+            "DBClusterSnapshotAttributesResult": {
+                "DBClusterSnapshotIdentifier": db_cluster_snapshot_identifier,
+                "DBClusterSnapshotAttributes": db_cluster_snapshot_attributes_result,
+            }
+        }
+        return self.serialize(result)
 
-    def modify_db_cluster_snapshot_attribute(self) -> str:
+    def modify_db_cluster_snapshot_attribute(self) -> TYPE_RESPONSE:
         params = self._get_params()
         db_cluster_snapshot_identifier = params["DBClusterSnapshotIdentifier"]
         db_cluster_snapshot_attributes_result = (
@@ -865,13 +954,15 @@ class RDSResponse(BaseResponse):
                 values_to_remove=params.get("ValuesToRemove"),
             )
         )
-        template = self.response_template(MODIFY_DB_CLUSTER_SNAPSHOT_ATTRIBUTE_TEMPLATE)
-        return template.render(
-            db_cluster_snapshot_attributes_result=db_cluster_snapshot_attributes_result,
-            db_cluster_snapshot_identifier=db_cluster_snapshot_identifier,
-        )
+        result = {
+            "DBClusterSnapshotAttributesResult": {
+                "DBClusterSnapshotIdentifier": db_cluster_snapshot_identifier,
+                "DBClusterSnapshotAttributes": db_cluster_snapshot_attributes_result,
+            }
+        }
+        return self.serialize(result)
 
-    def describe_db_proxies(self) -> str:
+    def describe_db_proxies(self) -> TYPE_RESPONSE:
         params = self._get_params()
         db_proxy_name = params.get("DBProxyName")
         # filters = params.get("Filters")
@@ -880,11 +971,13 @@ class RDSResponse(BaseResponse):
             db_proxy_name=db_proxy_name,
             # filters=filters,
         )
-        template = self.response_template(DESCRIBE_DB_PROXIES_TEMPLATE)
-        rendered = template.render(dbproxies=db_proxies, marker=marker)
-        return rendered
+        result = {
+            "DBProxies": db_proxies,
+            "Marker": marker,
+        }
+        return self.serialize(result)
 
-    def create_db_proxy(self) -> str:
+    def create_db_proxy(self) -> TYPE_RESPONSE:
         params = self._get_params()
         db_proxy_name = params["DBProxyName"]
         engine_family = params["EngineFamily"]
@@ -908,10 +1001,10 @@ class RDSResponse(BaseResponse):
             debug_logging=debug_logging,
             tags=tags,
         )
-        template = self.response_template(CREATE_DB_PROXY_TEMPLATE)
-        return template.render(dbproxy=db_proxy)
+        result = {"DBProxy": db_proxy}
+        return self.serialize(result)
 
-    def register_db_proxy_targets(self) -> str:
+    def register_db_proxy_targets(self) -> TYPE_RESPONSE:
         db_proxy_name = self._get_param("DBProxyName")
         target_group_name = self._get_param("TargetGroupName")
         db_cluster_identifiers = self._get_params().get("DBClusterIdentifiers", [])
@@ -922,11 +1015,14 @@ class RDSResponse(BaseResponse):
             db_cluster_identifiers=db_cluster_identifiers,
             db_instance_identifiers=db_instance_identifiers,
         )
+        result = {
+            "DBProxyTargets": [
+                DBProxyTargetDTO(target, registering=True) for target in targets
+            ]
+        }
+        return self.serialize(result)
 
-        template = self.response_template(REGISTER_DB_PROXY_TARGET)
-        return template.render(targets=targets)
-
-    def deregister_db_proxy_targets(self) -> str:
+    def deregister_db_proxy_targets(self) -> TYPE_RESPONSE:
         db_proxy_name = self._get_param("DBProxyName")
         target_group_name = self._get_param("TargetGroupName")
         db_cluster_identifiers = self._get_params().get("DBClusterIdentifiers", [])
@@ -937,36 +1033,34 @@ class RDSResponse(BaseResponse):
             db_cluster_identifiers=db_cluster_identifiers,
             db_instance_identifiers=db_instance_identifiers,
         )
+        return self.serialize({})
 
-        template = self.response_template(DEREGISTER_DB_PROXY_TARGET)
-        return template.render()
-
-    def describe_db_proxy_targets(self) -> str:
+    def describe_db_proxy_targets(self) -> TYPE_RESPONSE:
         proxy_name = self._get_param("DBProxyName")
         targets = self.backend.describe_db_proxy_targets(proxy_name=proxy_name)
-        template = self.response_template(DESCRIBE_DB_PROXY_TARGETS)
-        return template.render(targets=targets)
+        result = {"Targets": [DBProxyTargetDTO(target) for target in targets]}
+        return self.serialize(result)
 
-    def delete_db_proxy(self) -> str:
+    def delete_db_proxy(self) -> TYPE_RESPONSE:
         proxy_name = self._get_param("DBProxyName")
         proxy = self.backend.delete_db_proxy(proxy_name=proxy_name)
-        template = self.response_template(DELETE_DB_PROXY_TEMPLATE)
-        return template.render(dbproxy=proxy)
+        result = {"DBProxy": proxy}
+        return self.serialize(result)
 
-    def describe_db_proxy_target_groups(self) -> str:
+    def describe_db_proxy_target_groups(self) -> TYPE_RESPONSE:
         proxy_name = self._get_param("DBProxyName")
         groups = self.backend.describe_db_proxy_target_groups(proxy_name=proxy_name)
-        template = self.response_template(DESCRIBE_DB_PROXY_TARGET_GROUPS)
-        return template.render(groups=groups)
+        result = {"TargetGroups": [DBProxyTargetGroupDTO(group) for group in groups]}
+        return self.serialize(result)
 
-    def modify_db_proxy_target_group(self) -> str:
+    def modify_db_proxy_target_group(self) -> TYPE_RESPONSE:
         proxy_name = self._get_param("DBProxyName")
         config = self._get_params().get("ConnectionPoolConfig", {})
         group = self.backend.modify_db_proxy_target_group(
             proxy_name=proxy_name, config=config
         )
-        template = self.response_template(MODIFY_DB_PROXY_TARGET_GROUP)
-        return template.render(group=group)
+        result = {"DBProxyTargetGroup": DBProxyTargetGroupDTO(group)}
+        return self.serialize(result)
 
     def _paginate(self, resources: List[Any]) -> Tuple[List[Any], Optional[str]]:
         from moto.rds.exceptions import InvalidParameterValue
@@ -990,905 +1084,3 @@ class RDSResponse(BaseResponse):
         if len(all_resources) > start + page_size:
             next_marker = paginated_resources[-1].name
         return paginated_resources, next_marker
-
-
-CREATE_DATABASE_TEMPLATE = """<CreateDBInstanceResponse xmlns="http://rds.amazonaws.com/doc/2014-09-01/">
-  <CreateDBInstanceResult>
-  {{ database.to_xml() }}
-  </CreateDBInstanceResult>
-  <ResponseMetadata>
-    <RequestId>523e3218-afc7-11c3-90f5-f90431260ab4</RequestId>
-  </ResponseMetadata>
-</CreateDBInstanceResponse>"""
-
-CREATE_DATABASE_REPLICA_TEMPLATE = """<CreateDBInstanceReadReplicaResponse xmlns="http://rds.amazonaws.com/doc/2014-09-01/">
-  <CreateDBInstanceReadReplicaResult>
-  {{ database.to_xml() }}
-  </CreateDBInstanceReadReplicaResult>
-  <ResponseMetadata>
-    <RequestId>5e60c46d-a844-11e4-bb68-17f36418e58f</RequestId>
-  </ResponseMetadata>
-</CreateDBInstanceReadReplicaResponse>"""
-
-DESCRIBE_DATABASES_TEMPLATE = """<DescribeDBInstancesResponse xmlns="http://rds.amazonaws.com/doc/2014-09-01/">
-  <DescribeDBInstancesResult>
-    <DBInstances>
-    {%- for database in databases -%}
-      {{ database.to_xml() }}
-    {%- endfor -%}
-    </DBInstances>
-    {% if marker %}
-    <Marker>{{ marker }}</Marker>
-    {% endif %}
-  </DescribeDBInstancesResult>
-  <ResponseMetadata>
-    <RequestId>523e3218-afc7-11c3-90f5-f90431260ab4</RequestId>
-  </ResponseMetadata>
-</DescribeDBInstancesResponse>"""
-
-MODIFY_DATABASE_TEMPLATE = """<ModifyDBInstanceResponse xmlns="http://rds.amazonaws.com/doc/2014-09-01/">
-  <ModifyDBInstanceResult>
-  {{ database.to_xml() }}
-  </ModifyDBInstanceResult>
-  <ResponseMetadata>
-    <RequestId>bb58476c-a1a8-11e4-99cf-55e92d4bbada</RequestId>
-  </ResponseMetadata>
-</ModifyDBInstanceResponse>"""
-
-PROMOTE_REPLICA_TEMPLATE = """<PromoteReadReplicaResponse xmlns="http://rds.amazonaws.com/doc/2014-09-01/">
-  <PromoteReadReplicaResult>
-  {{ database.to_xml() }}
-  </PromoteReadReplicaResult>
-  <ResponseMetadata>
-    <RequestId>8e8c0d64-be21-11d3-a71c-13dc2f771e41</RequestId>
-  </ResponseMetadata>
-</PromoteReadReplicaResponse>"""
-
-REBOOT_DATABASE_TEMPLATE = """<RebootDBInstanceResponse xmlns="http://rds.amazonaws.com/doc/2014-09-01/">
-  <RebootDBInstanceResult>
-  {{ database.to_xml() }}
-  </RebootDBInstanceResult>
-  <ResponseMetadata>
-    <RequestId>d55711cb-a1ab-11e4-99cf-55e92d4bbada</RequestId>
-  </ResponseMetadata>
-</RebootDBInstanceResponse>"""
-
-START_DATABASE_TEMPLATE = """<StartDBInstanceResponse xmlns="http://rds.amazonaws.com/doc/2014-10-31/">
-  <StartDBInstanceResult>
-  {{ database.to_xml() }}
-  </StartDBInstanceResult>
-  <ResponseMetadata>
-    <RequestId>523e3218-afc7-11c3-90f5-f90431260ab9</RequestId>
-  </ResponseMetadata>
-</StartDBInstanceResponse>"""
-
-STOP_DATABASE_TEMPLATE = """<StopDBInstanceResponse xmlns="http://rds.amazonaws.com/doc/2014-10-31/">
-  <StopDBInstanceResult>
-  {{ database.to_xml() }}
-  </StopDBInstanceResult>
-  <ResponseMetadata>
-    <RequestId>523e3218-afc7-11c3-90f5-f90431260ab8</RequestId>
-  </ResponseMetadata>
-</StopDBInstanceResponse>"""
-
-DELETE_DATABASE_TEMPLATE = """<DeleteDBInstanceResponse xmlns="http://rds.amazonaws.com/doc/2014-09-01/">
-  <DeleteDBInstanceResult>
-    {{ database.to_xml() }}
-  </DeleteDBInstanceResult>
-  <ResponseMetadata>
-    <RequestId>7369556f-b70d-11c3-faca-6ba18376ea1b</RequestId>
-  </ResponseMetadata>
-</DeleteDBInstanceResponse>"""
-
-DELETE_CLUSTER_TEMPLATE = """<DeleteDBClusterResponse xmlns="http://rds.amazonaws.com/doc/2014-09-01/">
-  <DeleteDBClusterResult>
-    {{ cluster.to_xml() }}
-  </DeleteDBClusterResult>
-  <ResponseMetadata>
-    <RequestId>7369556f-b70d-11c3-faca-6ba18376ea1b</RequestId>
-  </ResponseMetadata>
-</DeleteDBClusterResponse>"""
-
-RESTORE_INSTANCE_FROM_SNAPSHOT_TEMPLATE = """<RestoreDBInstanceFromDBSnapshotResponse xmlns="http://rds.amazonaws.com/doc/2014-09-01/">
-  <RestoreDBInstanceFromDBSnapshotResult>
-  {{ database.to_xml() }}
-  </RestoreDBInstanceFromDBSnapshotResult>
-  <ResponseMetadata>
-    <RequestId>523e3218-afc7-11c3-90f5-f90431260ab4</RequestId>
-  </ResponseMetadata>
-</RestoreDBInstanceFromDBSnapshotResponse>"""
-
-
-RESTORE_INSTANCE_TO_POINT_IN_TIME_TEMPLATE = """<RestoreDBInstanceToPointInTimeResponse xmlns="http://rds.amazonaws.com/doc/2014-09-01/">
-  <RestoreDBInstanceToPointInTimeResult>
-  {{ database.to_xml() }}
-  </RestoreDBInstanceToPointInTimeResult>
-  <ResponseMetadata>
-    <RequestId>523e3218-afc7-11c3-90f5-f90431260ab4</RequestId>
-  </ResponseMetadata>
-</RestoreDBInstanceToPointInTimeResponse>"""
-
-CREATE_SNAPSHOT_TEMPLATE = """<CreateDBSnapshotResponse xmlns="http://rds.amazonaws.com/doc/2014-09-01/">
-  <CreateDBSnapshotResult>
-  {{ snapshot.to_xml() }}
-  </CreateDBSnapshotResult>
-  <ResponseMetadata>
-    <RequestId>523e3218-afc7-11c3-90f5-f90431260ab4</RequestId>
-  </ResponseMetadata>
-</CreateDBSnapshotResponse>
-"""
-
-COPY_SNAPSHOT_TEMPLATE = """<CopyDBSnapshotResponse xmlns="http://rds.amazonaws.com/doc/2014-09-01/">
-  <CopyDBSnapshotResult>
-  {{ snapshot.to_xml() }}
-  </CopyDBSnapshotResult>
-  <ResponseMetadata>
-    <RequestId>523e3218-afc7-11c3-90f5-f90431260ab4</RequestId>
-  </ResponseMetadata>
-</CopyDBSnapshotResponse>
-"""
-
-DESCRIBE_SNAPSHOTS_TEMPLATE = """<DescribeDBSnapshotsResponse xmlns="http://rds.amazonaws.com/doc/2014-09-01/">
-  <DescribeDBSnapshotsResult>
-    <DBSnapshots>
-    {%- for snapshot in snapshots -%}
-      {{ snapshot.to_xml() }}
-    {%- endfor -%}
-    </DBSnapshots>
-    {% if marker %}
-    <Marker>{{ marker }}</Marker>
-    {% endif %}
-  </DescribeDBSnapshotsResult>
-  <ResponseMetadata>
-    <RequestId>523e3218-afc7-11c3-90f5-f90431260ab4</RequestId>
-  </ResponseMetadata>
-</DescribeDBSnapshotsResponse>"""
-
-DELETE_SNAPSHOT_TEMPLATE = """<DeleteDBSnapshotResponse xmlns="http://rds.amazonaws.com/doc/2014-09-01/">
-  <DeleteDBSnapshotResult>
-  {{ snapshot.to_xml() }}
-  </DeleteDBSnapshotResult>
-  <ResponseMetadata>
-    <RequestId>523e3218-afc7-11c3-90f5-f90431260ab4</RequestId>
-  </ResponseMetadata>
-</DeleteDBSnapshotResponse>
-"""
-
-CREATE_SECURITY_GROUP_TEMPLATE = """<CreateDBSecurityGroupResponse xmlns="http://rds.amazonaws.com/doc/2014-09-01/">
-  <CreateDBSecurityGroupResult>
-  {{ security_group.to_xml() }}
-  </CreateDBSecurityGroupResult>
-  <ResponseMetadata>
-    <RequestId>462165d0-a77a-11e4-a5fa-75b30c556f97</RequestId>
-  </ResponseMetadata>
-</CreateDBSecurityGroupResponse>"""
-
-DESCRIBE_SECURITY_GROUPS_TEMPLATE = """<DescribeDBSecurityGroupsResponse xmlns="http://rds.amazonaws.com/doc/2014-09-01/">
-  <DescribeDBSecurityGroupsResult>
-    <DBSecurityGroups>
-    {% for security_group in security_groups %}
-      {{ security_group.to_xml() }}
-    {% endfor %}
-   </DBSecurityGroups>
-  </DescribeDBSecurityGroupsResult>
-  <ResponseMetadata>
-    <RequestId>5df2014e-a779-11e4-bdb0-594def064d0c</RequestId>
-  </ResponseMetadata>
-</DescribeDBSecurityGroupsResponse>"""
-
-DELETE_SECURITY_GROUP_TEMPLATE = """<DeleteDBSecurityGroupResponse xmlns="http://rds.amazonaws.com/doc/2014-09-01/">
-  <ResponseMetadata>
-    <RequestId>97e846bd-a77d-11e4-ac58-91351c0f3426</RequestId>
-  </ResponseMetadata>
-</DeleteDBSecurityGroupResponse>"""
-
-AUTHORIZE_SECURITY_GROUP_TEMPLATE = """<AuthorizeDBSecurityGroupIngressResponse xmlns="http://rds.amazonaws.com/doc/2014-09-01/">
-  <AuthorizeDBSecurityGroupIngressResult>
-  {{ security_group.to_xml() }}
-  </AuthorizeDBSecurityGroupIngressResult>
-  <ResponseMetadata>
-    <RequestId>75d32fd5-a77e-11e4-8892-b10432f7a87d</RequestId>
-  </ResponseMetadata>
-</AuthorizeDBSecurityGroupIngressResponse>"""
-
-CREATE_SUBNET_GROUP_TEMPLATE = """<CreateDBSubnetGroupResponse xmlns="http://rds.amazonaws.com/doc/2014-09-01/">
-  <CreateDBSubnetGroupResult>
-  {{ subnet_group.to_xml() }}
-  </CreateDBSubnetGroupResult>
-  <ResponseMetadata>
-    <RequestId>3a401b3f-bb9e-11d3-f4c6-37db295f7674</RequestId>
-  </ResponseMetadata>
-</CreateDBSubnetGroupResponse>"""
-
-DESCRIBE_SUBNET_GROUPS_TEMPLATE = """<DescribeDBSubnetGroupsResponse xmlns="http://rds.amazonaws.com/doc/2014-09-01/">
-  <DescribeDBSubnetGroupsResult>
-    <DBSubnetGroups>
-    {% for subnet_group in subnet_groups %}
-      {{ subnet_group.to_xml() }}
-    {% endfor %}
-    </DBSubnetGroups>
-  </DescribeDBSubnetGroupsResult>
-  <ResponseMetadata>
-    <RequestId>b783db3b-b98c-11d3-fbc7-5c0aad74da7c</RequestId>
-  </ResponseMetadata>
-</DescribeDBSubnetGroupsResponse>"""
-
-MODIFY_SUBNET_GROUPS_TEMPLATE = """<ModifyDBSubnetGroupResponse xmlns="http://rds.amazonaws.com/doc/2014-09-01/">
-  <ModifyDBSubnetGroupResult>
-    {{ subnet_group.to_xml() }}
-  </ModifyDBSubnetGroupResult>
-  <ResponseMetadata>
-    <RequestId>b783db3b-b98c-11d3-fbc7-5c0aad74da7c</RequestId>
-  </ResponseMetadata>
-</ModifyDBSubnetGroupResponse>"""
-
-DELETE_SUBNET_GROUP_TEMPLATE = """<DeleteDBSubnetGroupResponse xmlns="http://rds.amazonaws.com/doc/2014-09-01/">
-  <ResponseMetadata>
-    <RequestId>13785dd5-a7fc-11e4-bb9c-7f371d0859b0</RequestId>
-  </ResponseMetadata>
-</DeleteDBSubnetGroupResponse>"""
-
-CREATE_OPTION_GROUP_TEMPLATE = """<CreateOptionGroupResponse xmlns="http://rds.amazonaws.com/doc/2014-09-01/">
-  <CreateOptionGroupResult>
-  {{ option_group.to_xml() }}
-  </CreateOptionGroupResult>
-  <ResponseMetadata>
-    <RequestId>1e38dad4-9f50-11e4-87ea-a31c60ed2e36</RequestId>
-  </ResponseMetadata>
-</CreateOptionGroupResponse>"""
-
-DELETE_OPTION_GROUP_TEMPLATE = """<DeleteOptionGroupResponse xmlns="http://rds.amazonaws.com/doc/2014-09-01/">
-  <ResponseMetadata>
-    <RequestId>e2590367-9fa2-11e4-99cf-55e92d41c60e</RequestId>
-  </ResponseMetadata>
-</DeleteOptionGroupResponse>"""
-
-DESCRIBE_OPTION_GROUP_TEMPLATE = """<DescribeOptionGroupsResponse xmlns="http://rds.amazonaws.com/doc/2014-09-01/">
-  <DescribeOptionGroupsResult>
-    <OptionGroupsList>
-    {%- for option_group in option_groups -%}
-      {{ option_group.to_xml() }}
-    {%- endfor -%}
-    </OptionGroupsList>
-  </DescribeOptionGroupsResult>
-  <ResponseMetadata>
-    <RequestId>4caf445d-9fbc-11e4-87ea-a31c60ed2e36</RequestId>
-  </ResponseMetadata>
-</DescribeOptionGroupsResponse>"""
-
-DESCRIBE_OPTION_GROUP_OPTIONS_TEMPLATE = """<DescribeOptionGroupOptionsResponse xmlns="http://rds.amazonaws.com/doc/2014-09-01/">
-  <DescribeOptionGroupOptionsResult>
-    <OptionGroupOptions>
-    {%- for option_group_option in option_group_options -%}
-      {{ option_group_option.to_xml() }}
-    {%- endfor -%}
-    </OptionGroupOptions>
-  </DescribeOptionGroupOptionsResult>
-  <ResponseMetadata>
-    <RequestId>457f7bb8-9fbf-11e4-9084-5754f80d5144</RequestId>
-  </ResponseMetadata>
-</DescribeOptionGroupOptionsResponse>"""
-
-MODIFY_OPTION_GROUP_TEMPLATE = """<ModifyOptionGroupResponse xmlns="http://rds.amazonaws.com/doc/2014-09-01/">
-  <ModifyOptionGroupResult>
-    {{ option_group.to_xml() }}
-  </ModifyOptionGroupResult>
-  <ResponseMetadata>
-    <RequestId>ce9284a5-a0de-11e4-b984-a11a53e1f328</RequestId>
-  </ResponseMetadata>
-</ModifyOptionGroupResponse>"""
-
-CREATE_DB_PARAMETER_GROUP_TEMPLATE = """<CreateDBParameterGroupResponse xmlns="http://rds.amazonaws.com/doc/2014-09-01/">
-  <CreateDBParameterGroupResult>
-    {{ db_parameter_group.to_xml() }}
-  </CreateDBParameterGroupResult>
-  <ResponseMetadata>
-    <RequestId>7805c127-af22-11c3-96ac-6999cc5f7e72</RequestId>
-  </ResponseMetadata>
-</CreateDBParameterGroupResponse>"""
-
-DESCRIBE_DB_PARAMETER_GROUPS_TEMPLATE = """<DescribeDBParameterGroupsResponse xmlns="http://rds.amazonaws.com/doc/2014-09-01/">
-  <DescribeDBParameterGroupsResult>
-    <DBParameterGroups>
-    {%- for db_parameter_group in db_parameter_groups -%}
-      {{ db_parameter_group.to_xml() }}
-    {%- endfor -%}
-    </DBParameterGroups>
-  </DescribeDBParameterGroupsResult>
-  <ResponseMetadata>
-    <RequestId>b75d527a-b98c-11d3-f272-7cd6cce12cc5</RequestId>
-  </ResponseMetadata>
-</DescribeDBParameterGroupsResponse>"""
-
-MODIFY_DB_PARAMETER_GROUP_TEMPLATE = """<ModifyDBParameterGroupResponse xmlns="http://rds.amazonaws.com/doc/2014-09-01/">
-  <ModifyDBParameterGroupResult>
-    <DBParameterGroupName>{{ db_parameter_group.name }}</DBParameterGroupName>
-  </ModifyDBParameterGroupResult>
-  <ResponseMetadata>
-    <RequestId>12d7435e-bba0-11d3-fe11-33d33a9bb7e3</RequestId>
-  </ResponseMetadata>
-</ModifyDBParameterGroupResponse>"""
-
-DELETE_DB_PARAMETER_GROUP_TEMPLATE = """<DeleteDBParameterGroupResponse xmlns="http://rds.amazonaws.com/doc/2014-09-01/">
-  <ResponseMetadata>
-    <RequestId>cad6c267-ba25-11d3-fe11-33d33a9bb7e3</RequestId>
-  </ResponseMetadata>
-</DeleteDBParameterGroupResponse>"""
-
-DESCRIBE_DB_PARAMETERS_TEMPLATE = """<DescribeDBParametersResponse xmlns="http://rds.amazonaws.com/doc/2014-09-01/">
-  <DescribeDBParametersResult>
-    <Parameters>
-      {%- for db_parameter_name, db_parameter in db_parameter_group.parameters.items() -%}
-      <Parameter>
-        {%- for parameter_name, parameter_value in db_parameter.items() -%}
-        <{{ parameter_name }}>{{ parameter_value }}</{{ parameter_name }}>
-        {%- endfor -%}
-      </Parameter>
-      {%- endfor -%}
-    </Parameters>
-  </DescribeDBParametersResult>
-  <ResponseMetadata>
-    <RequestId>8c40488f-b9ff-11d3-a15e-7ac49293f4fa</RequestId>
-  </ResponseMetadata>
-</DescribeDBParametersResponse>
-"""
-
-DESCRIBE_DB_CLUSTER_PARAMETERS_TEMPLATE = """<DescribeDBClusterParametersResponse xmlns="http://rds.amazonaws.com/doc/2014-09-01/">
-  <DescribeDBClusterParametersResult>
-    <Parameters>
-      {%- for param in db_parameter_group -%}
-      <Parameter>
-        {%- for parameter_name, parameter_value in db_parameter.items() -%}
-        <{{ parameter_name }}>{{ parameter_value }}</{{ parameter_name }}>
-        {%- endfor -%}
-      </Parameter>
-      {%- endfor -%}
-    </Parameters>
-  </DescribeDBClusterParametersResult>
-  <ResponseMetadata>
-    <RequestId>8c40488f-b9ff-11d3-a15e-7ac49293f4fa</RequestId>
-  </ResponseMetadata>
-</DescribeDBClusterParametersResponse>
-"""
-
-LIST_TAGS_FOR_RESOURCE_TEMPLATE = """<ListTagsForResourceResponse xmlns="http://rds.amazonaws.com/doc/2014-10-31/">
-  <ListTagsForResourceResult>
-    <TagList>
-    {%- for tag in tags -%}
-      <Tag>
-        <Key>{{ tag['Key'] }}</Key>
-        <Value>{{ tag['Value'] }}</Value>
-      </Tag>
-    {%- endfor -%}
-    </TagList>
-  </ListTagsForResourceResult>
-  <ResponseMetadata>
-    <RequestId>8c21ba39-a598-11e4-b688-194eaf8658fa</RequestId>
-  </ResponseMetadata>
-</ListTagsForResourceResponse>"""
-
-ADD_TAGS_TO_RESOURCE_TEMPLATE = """<AddTagsToResourceResponse xmlns="http://rds.amazonaws.com/doc/2014-10-31/">
-  <ResponseMetadata>
-    <RequestId>b194d9ca-a664-11e4-b688-194eaf8658fa</RequestId>
-  </ResponseMetadata>
-</AddTagsToResourceResponse>"""
-
-REMOVE_TAGS_FROM_RESOURCE_TEMPLATE = """<RemoveTagsFromResourceResponse xmlns="http://rds.amazonaws.com/doc/2014-10-31/">
-  <ResponseMetadata>
-    <RequestId>b194d9ca-a664-11e4-b688-194eaf8658fa</RequestId>
-  </ResponseMetadata>
-</RemoveTagsFromResourceResponse>"""
-
-CREATE_DB_CLUSTER_TEMPLATE = """<CreateDBClusterResponse xmlns="http://rds.amazonaws.com/doc/2014-09-01/">
-  <CreateDBClusterResult>
-  {{ cluster.to_xml(initial=True) }}
-  </CreateDBClusterResult>
-  <ResponseMetadata>
-    <RequestId>523e3218-afc7-11c3-90f5-f90431260ab4</RequestId>
-  </ResponseMetadata>
-</CreateDBClusterResponse>"""
-
-MODIFY_DB_CLUSTER_TEMPLATE = """<ModifyDBClusterResponse xmlns="http://rds.amazonaws.com/doc/2014-10-31/">
-  <ModifyDBClusterResult>
-  {{ cluster.to_xml() }}
-  </ModifyDBClusterResult>
-  <ResponseMetadata>
-    <RequestId>69673d54-e48e-4ba4-9333-c5a6c1e7526a</RequestId>
-  </ResponseMetadata>
-</ModifyDBClusterResponse>"""
-
-DESCRIBE_CLUSTERS_TEMPLATE = """<DescribeDBClustersResponse xmlns="http://rds.amazonaws.com/doc/2014-09-01/">
-  <DescribeDBClustersResult>
-    <DBClusters>
-    {%- for cluster in clusters -%}
-      {{ cluster.to_xml() }}
-    {%- endfor -%}
-    </DBClusters>
-    {% if marker %}
-    <Marker>{{ marker }}</Marker>
-    {% endif %}
-  </DescribeDBClustersResult>
-  <ResponseMetadata>
-    <RequestId>523e3218-afc7-11c3-90f5-f90431260ab4</RequestId>
-  </ResponseMetadata>
-</DescribeDBClustersResponse>"""
-
-START_CLUSTER_TEMPLATE = """<StartDBClusterResponse xmlns="http://rds.amazonaws.com/doc/2014-10-31/">
-  <StartDBClusterResult>
-  {{ cluster.to_xml() }}
-  </StartDBClusterResult>
-  <ResponseMetadata>
-    <RequestId>523e3218-afc7-11c3-90f5-f90431260ab9</RequestId>
-  </ResponseMetadata>
-</StartDBClusterResponse>"""
-
-STOP_CLUSTER_TEMPLATE = """<StopDBClusterResponse xmlns="http://rds.amazonaws.com/doc/2014-10-31/">
-  <StopDBClusterResult>
-  {{ cluster.to_xml() }}
-  </StopDBClusterResult>
-  <ResponseMetadata>
-    <RequestId>523e3218-afc7-11c3-90f5-f90431260ab8</RequestId>
-  </ResponseMetadata>
-</StopDBClusterResponse>"""
-
-RESTORE_CLUSTER_FROM_SNAPSHOT_TEMPLATE = """<RestoreDBClusterFromDBSnapshotResponse xmlns="http://rds.amazonaws.com/doc/2014-09-01/">
-  <RestoreDBClusterFromSnapshotResult>
-  {{ cluster.to_xml() }}
-  </RestoreDBClusterFromSnapshotResult>
-  <ResponseMetadata>
-    <RequestId>523e3218-afc7-11c3-90f5-f90431260ab4</RequestId>
-  </ResponseMetadata>
-</RestoreDBClusterFromDBSnapshotResponse>
-"""
-
-CREATE_CLUSTER_SNAPSHOT_TEMPLATE = """<CreateDBClusterSnapshotResponse xmlns="http://rds.amazonaws.com/doc/2014-09-01/">
-  <CreateDBClusterSnapshotResult>
-  {{ snapshot.to_xml() }}
-  </CreateDBClusterSnapshotResult>
-  <ResponseMetadata>
-    <RequestId>523e3218-afc7-11c3-90f5-f90431260ab4</RequestId>
-  </ResponseMetadata>
-</CreateDBClusterSnapshotResponse>
-"""
-
-COPY_CLUSTER_SNAPSHOT_TEMPLATE = """<CopyDBClusterSnapshotResponse xmlns="http://rds.amazonaws.com/doc/2014-09-01/">
-  <CopyDBClusterSnapshotResult>
-  {{ snapshot.to_xml() }}
-  </CopyDBClusterSnapshotResult>
-  <ResponseMetadata>
-    <RequestId>523e3218-afc7-11c3-90f5-f90431260ab4</RequestId>
-  </ResponseMetadata>
-</CopyDBClusterSnapshotResponse>
-"""
-
-DESCRIBE_CLUSTER_SNAPSHOTS_TEMPLATE = """<DescribeDBClusterSnapshotsResponse xmlns="http://rds.amazonaws.com/doc/2014-09-01/">
-  <DescribeDBClusterSnapshotsResult>
-    <DBClusterSnapshots>
-    {%- for snapshot in snapshots -%}
-      {{ snapshot.to_xml() }}
-    {%- endfor -%}
-    </DBClusterSnapshots>
-    {% if marker %}
-    <Marker>{{ marker }}</Marker>
-    {% endif %}
-  </DescribeDBClusterSnapshotsResult>
-  <ResponseMetadata>
-    <RequestId>523e3218-afc7-11c3-90f5-f90431260ab4</RequestId>
-  </ResponseMetadata>
-</DescribeDBClusterSnapshotsResponse>"""
-
-DELETE_CLUSTER_SNAPSHOT_TEMPLATE = """<DeleteDBClusterSnapshotResponse xmlns="http://rds.amazonaws.com/doc/2014-09-01/">
-  <DeleteDBClusterSnapshotResult>
-  {{ snapshot.to_xml() }}
-  </DeleteDBClusterSnapshotResult>
-  <ResponseMetadata>
-    <RequestId>523e3218-afc7-11c3-90f5-f90431260ab4</RequestId>
-  </ResponseMetadata>
-</DeleteDBClusterSnapshotResponse>
-"""
-
-START_EXPORT_TASK_TEMPLATE = """<StartExportTaskResponse xmlns="http://rds.amazonaws.com/doc/2014-09-01/">
-  <StartExportTaskResult>
-  {{ task.to_xml() }}
-  </StartExportTaskResult>
-  <ResponseMetadata>
-    <RequestId>523e3218-afc7-11c3-90f5-f90431260ab4</RequestId>
-  </ResponseMetadata>
-</StartExportTaskResponse>
-"""
-
-CANCEL_EXPORT_TASK_TEMPLATE = """<CancelExportTaskResponse xmlns="http://rds.amazonaws.com/doc/2014-09-01/">
-  <CancelExportTaskResult>
-  {{ task.to_xml() }}
-  </CancelExportTaskResult>
-  <ResponseMetadata>
-    <RequestId>523e3218-afc7-11c3-90f5-f90431260ab4</RequestId>
-  </ResponseMetadata>
-</CancelExportTaskResponse>
-"""
-
-DESCRIBE_EXPORT_TASKS_TEMPLATE = """<DescribeExportTasksResponse xmlns="http://rds.amazonaws.com/doc/2014-09-01/">
-  <DescribeExportTasksResult>
-    <ExportTasks>
-    {%- for task in tasks -%}
-      <ExportTask>{{ task.to_xml() }}</ExportTask>
-    {%- endfor -%}
-    </ExportTasks>
-    {% if marker %}
-    <Marker>{{ marker }}</Marker>
-    {% endif %}
-  </DescribeExportTasksResult>
-  <ResponseMetadata>
-    <RequestId>523e3218-afc7-11c3-90f5-f90431260ab4</RequestId>
-  </ResponseMetadata>
-</DescribeExportTasksResponse>
-"""
-
-CREATE_EVENT_SUBSCRIPTION_TEMPLATE = """<CreateEventSubscriptionResponse xmlns="http://rds.amazonaws.com/doc/2014-09-01/">
-  <CreateEventSubscriptionResult>
-  {{ subscription.to_xml() }}
-  </CreateEventSubscriptionResult>
-  <ResponseMetadata>
-    <RequestId>523e3218-afc7-11c3-90f5-f90431260ab4</RequestId>
-  </ResponseMetadata>
-</CreateEventSubscriptionResponse>
-"""
-
-DELETE_EVENT_SUBSCRIPTION_TEMPLATE = """<DeleteEventSubscriptionResponse xmlns="http://rds.amazonaws.com/doc/2014-09-01/">
-  <DeleteEventSubscriptionResult>
-  {{ subscription.to_xml() }}
-  </DeleteEventSubscriptionResult>
-  <ResponseMetadata>
-    <RequestId>523e3218-afc7-11c3-90f5-f90431260ab4</RequestId>
-  </ResponseMetadata>
-</DeleteEventSubscriptionResponse>
-"""
-
-DESCRIBE_EVENT_SUBSCRIPTIONS_TEMPLATE = """<DescribeEventSubscriptionsResponse xmlns="http://rds.amazonaws.com/doc/2014-09-01/">
-  <DescribeEventSubscriptionsResult>
-    <EventSubscriptionsList>
-      {%- for subscription in subscriptions -%}
-        {{ subscription.to_xml() }}
-      {%- endfor -%}
-    </EventSubscriptionsList>
-  </DescribeEventSubscriptionsResult>
-  <ResponseMetadata>
-    <RequestId>523e3218-afc7-11c3-90f5-f90431260ab4</RequestId>
-  </ResponseMetadata>
-</DescribeEventSubscriptionsResponse>
-"""
-
-
-DESCRIBE_ORDERABLE_CLUSTER_OPTIONS = """<DescribeOrderableDBInstanceOptionsResponse xmlns="http://rds.amazonaws.com/doc/2014-10-31/">
-  <DescribeOrderableDBInstanceOptionsResult>
-    <OrderableDBInstanceOptions>
-    {% for option in options %}
-      <OrderableDBInstanceOption>
-        <OutpostCapable>false</OutpostCapable>
-        <AvailabilityZones>
-          {% for zone in option["AvailabilityZones"] %}
-          <AvailabilityZone>
-            <Name>{{ zone["Name"] }}</Name>
-          </AvailabilityZone>
-          {% endfor %}
-        </AvailabilityZones>
-        <SupportsStorageThroughput>{{ option["SupportsStorageThroughput"] }}</SupportsStorageThroughput>
-        <SupportedEngineModes>
-          <member>provisioned</member>
-        </SupportedEngineModes>
-        <SupportsGlobalDatabases>{{ option["SupportsGlobalDatabases"] }}</SupportsGlobalDatabases>
-        <SupportsClusters>{{ option["SupportsClusters"] }}</SupportsClusters>
-        <Engine>{{ option["Engine"] }}</Engine>
-        <SupportedActivityStreamModes/>
-        <SupportsEnhancedMonitoring>false</SupportsEnhancedMonitoring>
-        <EngineVersion>{{ option["EngineVersion"] }}</EngineVersion>
-        <ReadReplicaCapable>false</ReadReplicaCapable>
-        <Vpc>true</Vpc>
-        <DBInstanceClass>{{ option["DBInstanceClass"] }}</DBInstanceClass>
-        <SupportsStorageEncryption>{{ option["SupportsStorageEncryption"] }}</SupportsStorageEncryption>
-        <SupportsKerberosAuthentication>{{ option["SupportsKerberosAuthentication"] }}</SupportsKerberosAuthentication>
-        <SupportedNetworkTypes>
-          <member>IPV4</member>
-        </SupportedNetworkTypes>
-        <AvailableProcessorFeatures/>
-        <SupportsPerformanceInsights>{{ option["SupportsPerformanceInsights"] }}</SupportsPerformanceInsights>
-        <LicenseModel>{{ option["LicenseModel"] }}</LicenseModel>
-        <MultiAZCapable>{{ option["MultiAZCapable"] }}</MultiAZCapable>
-        <RequiresCustomProcessorFeatures>{{ option["RequiresCustomProcessorFeatures"] }}</RequiresCustomProcessorFeatures>
-        <StorageType>{{ option["StorageType"] }}</StorageType>
-        <SupportsIops>{{ option["SupportsIops"] }}</SupportsIops>
-        <SupportsIAMDatabaseAuthentication>{{ option["SupportsIAMDatabaseAuthentication"] }}</SupportsIAMDatabaseAuthentication>
-      </OrderableDBInstanceOption>
-      {% endfor %}
-    </OrderableDBInstanceOptions>
-    {% if marker %}
-    <Marker>{{ marker }}</Marker>
-    {% endif %}
-  </DescribeOrderableDBInstanceOptionsResult>
-  <ResponseMetadata>
-    <RequestId>54212dc5-16c4-4eb8-a88e-448691e877ab</RequestId>
-  </ResponseMetadata>
-</DescribeOrderableDBInstanceOptionsResponse>"""
-
-CREATE_DB_CLUSTER_PARAMETER_GROUP_TEMPLATE = """<CreateDBClusterParameterGroupResponse xmlns="http://rds.amazonaws.com/doc/2014-09-01/">
-  <CreateDBClusterParameterGroupResult>
-    {{ db_cluster_parameter_group.to_xml() }}
-  </CreateDBClusterParameterGroupResult>
-  <ResponseMetadata>
-    <RequestId>7805c127-af22-11c3-96ac-6999cc5f7e72</RequestId>
-  </ResponseMetadata>
-</CreateDBClusterParameterGroupResponse>"""
-
-
-DESCRIBE_DB_CLUSTER_PARAMETER_GROUPS_TEMPLATE = """<DescribeDBClusterParameterGroupsResponse xmlns="http://rds.amazonaws.com/doc/2014-09-01/">
-  <DescribeDBClusterParameterGroupsResult>
-    <DBClusterParameterGroups>
-    {%- for db_parameter_group in db_parameter_groups -%}
-      {{ db_parameter_group.to_xml() }}
-    {%- endfor -%}
-    </DBClusterParameterGroups>
-  </DescribeDBClusterParameterGroupsResult>
-  <ResponseMetadata>
-    <RequestId>b75d527a-b98c-11d3-f272-7cd6cce12cc5</RequestId>
-  </ResponseMetadata>
-</DescribeDBClusterParameterGroupsResponse>"""
-
-DELETE_DB_CLUSTER_PARAMETER_GROUP_TEMPLATE = """<DeleteDBClusterParameterGroupResponse xmlns="http://rds.amazonaws.com/doc/2014-09-01/">
-  <ResponseMetadata>
-    <RequestId>cad6c267-ba25-11d3-fe11-33d33a9bb7e3</RequestId>
-  </ResponseMetadata>
-</DeleteDBClusterParameterGroupResponse>"""
-
-PROMOTE_READ_REPLICA_DB_CLUSTER_TEMPLATE = """<PromoteReadReplicaDBClusterResponse xmlns="http://rds.amazonaws.com/doc/2014-09-01/">
-  <PromoteReadReplicaDBClusterResult>
-    {{ cluster.to_xml() }}
-  </PromoteReadReplicaDBClusterResult>
-  <ResponseMetadata>
-    <RequestId>7369556f-b70d-11c3-faca-6ba18376ea1b</RequestId>
-  </ResponseMetadata>
-</PromoteReadReplicaDBClusterResponse>"""
-
-DESCRIBE_DB_SNAPSHOT_ATTRIBUTES_TEMPLATE = """<DescribeDBSnapshotAttributesResponse xmlns="http://rds.amazonaws.com/doc/2014-10-31/">
-  <DescribeDBSnapshotAttributesResult>
-    <DBSnapshotAttributesResult>
-      <DBSnapshotAttributes>
-        {%- for attribute in db_snapshot_attributes_result -%}
-          <DBSnapshotAttribute>
-            <AttributeName>{{ attribute["AttributeName"] }}</AttributeName>
-            <AttributeValues>
-              {%- for value in attribute["AttributeValues"] -%}
-                <AttributeValue>{{ value }}</AttributeValue>
-              {%- endfor -%}
-            </AttributeValues>
-          </DBSnapshotAttribute>
-        {%- endfor -%}
-      </DBSnapshotAttributes>
-      <DBSnapshotIdentifier>{{ db_snapshot_identifier }}</DBSnapshotIdentifier>
-    </DBSnapshotAttributesResult>
-  </DescribeDBSnapshotAttributesResult>
-  <ResponseMetadata>
-    <RequestId>1549581b-12b7-11e3-895e-1334a</RequestId>
-  </ResponseMetadata>
-</DescribeDBSnapshotAttributesResponse>"""
-
-MODIFY_DB_SNAPSHOT_ATTRIBUTE_TEMPLATE = """<ModifyDBSnapshotAttributeResponse xmlns="http://rds.amazonaws.com/doc/2014-10-31/">
-  <ModifyDBSnapshotAttributeResult>
-    <DBSnapshotAttributesResult>
-      <DBSnapshotAttributes>
-        {%- for attribute in db_snapshot_attributes_result -%}
-          <DBSnapshotAttribute>
-            <AttributeName>{{ attribute["AttributeName"] }}</AttributeName>
-            <AttributeValues>
-              {%- for value in attribute["AttributeValues"] -%}
-                <AttributeValue>{{ value }}</AttributeValue>
-              {%- endfor -%}
-            </AttributeValues>
-          </DBSnapshotAttribute>
-        {%- endfor -%}
-      </DBSnapshotAttributes>
-      <DBSnapshotIdentifier>{{ db_snapshot_identifier }}</DBSnapshotIdentifier>
-    </DBSnapshotAttributesResult>
-  </ModifyDBSnapshotAttributeResult>
-  <ResponseMetadata>
-    <RequestId>1549581b-12b7-11e3-895e-1334aEXAMPLE</RequestId>
-  </ResponseMetadata>
-</ModifyDBSnapshotAttributeResponse>"""
-
-MODIFY_DB_CLUSTER_SNAPSHOT_ATTRIBUTE_TEMPLATE = """<ModifyDBClusterSnapshotAttributeResponse xmlns="http://rds.amazonaws.com/doc/2014-10-31/">
-  <ModifyDBClusterSnapshotAttributeResult>
-    <DBClusterSnapshotAttributesResult>
-      <DBClusterSnapshotAttributes>
-        {%- for attribute in db_cluster_snapshot_attributes_result -%}
-          <DBClusterSnapshotAttribute>
-            <AttributeName>{{ attribute["AttributeName"] }}</AttributeName>
-            <AttributeValues>
-              {%- for value in attribute["AttributeValues"] -%}
-                <AttributeValue>{{ value }}</AttributeValue>
-              {%- endfor -%}
-            </AttributeValues>
-          </DBClusterSnapshotAttribute>
-        {%- endfor -%}
-      </DBClusterSnapshotAttributes>
-      <DBClusterSnapshotIdentifier>{{ db_cluster_snapshot_identifier }}</DBClusterSnapshotIdentifier>
-    </DBClusterSnapshotAttributesResult>
-  </ModifyDBClusterSnapshotAttributeResult>
-  <ResponseMetadata>
-    <RequestId>1549581b-12b7-11e3-895e-1334a</RequestId>
-  </ResponseMetadata>
-</ModifyDBClusterSnapshotAttributeResponse>"""
-
-DESCRIBE_DB_CLUSTER_SNAPSHOT_ATTRIBUTES_TEMPLATE = """<DescribeDBClusterSnapshotAttributesResponse xmlns="http://rds.amazonaws.com/doc/2014-10-31/">
-  <DescribeDBClusterSnapshotAttributesResult>
-    <DBClusterSnapshotAttributesResult>
-      <DBClusterSnapshotAttributes>
-        {%- for attribute in db_cluster_snapshot_attributes_result -%}
-          <DBClusterSnapshotAttribute>
-            <AttributeName>{{ attribute["AttributeName"] }}</AttributeName>
-            <AttributeValues>
-              {%- for value in attribute["AttributeValues"] -%}
-                <AttributeValue>{{ value }}</AttributeValue>
-              {%- endfor -%}
-            </AttributeValues>
-          </DBClusterSnapshotAttribute> 
-        {%- endfor -%}
-      </DBClusterSnapshotAttributes>
-      <DBClusterSnapshotIdentifier>{{ db_cluster_snapshot_identifier }}</DBClusterSnapshotIdentifier>
-    </DBClusterSnapshotAttributesResult>
-  </DescribeDBClusterSnapshotAttributesResult>
-  <ResponseMetadata>
-    <RequestId>1549581b-12b7-11e3-895e-1334a</RequestId>
-  </ResponseMetadata>
-</DescribeDBClusterSnapshotAttributesResponse>"""
-
-CREATE_DB_PROXY_TEMPLATE = """<CreateDBProxyResponse xmlns="http://rds.amazonaws.com/doc/2014-10-31/">
-  <CreateDBProxyResult>
-    <DBProxy>
-    {{ dbproxy.to_xml() }}
-    </DBProxy>
-  </CreateDBProxyResult>
-  <ResponseMetadata>
-    <RequestId>1549581b-12b7-11e3-895e-1334aEXAMPLE</RequestId>
-  </ResponseMetadata>
-</CreateDBProxyResponse>"""
-
-DESCRIBE_DB_PROXIES_TEMPLATE = """<DescribeDBProxiesResponse xmlns="http://rds.amazonaws.com/doc/2014-10-31/">
-    <DescribeDBProxiesResult>
-        <DBProxies>
-          {% for dbproxy in dbproxies %}
-            <member>
-              {{ dbproxy.to_xml() }}
-            </member>
-          {% endfor %}
-        </DBProxies>
-    </DescribeDBProxiesResult>
-    <ResponseMetadata>
-        <RequestId>1549581b-12b7-11e3-895e-1334a</RequestId>
-    </ResponseMetadata>
-</DescribeDBProxiesResponse>
-"""
-
-CREATE_GLOBAL_CLUSTER_TEMPLATE = """<CreateGlobalClusterResponse xmlns="http://rds.amazonaws.com/doc/2014-10-31/">
-  <ResponseMetadata>
-    <RequestId>1549581b-12b7-11e3-895e-1334aEXAMPLE</RequestId>
-  </ResponseMetadata>
-  <CreateGlobalClusterResult>
-  <GlobalCluster>
-    {{ cluster.to_xml() }}
-  </GlobalCluster>
-  </CreateGlobalClusterResult>
-</CreateGlobalClusterResponse>"""
-
-DELETE_GLOBAL_CLUSTER_TEMPLATE = """<DeleteGlobalClusterResponse xmlns="http://rds.amazonaws.com/doc/2014-10-31/">
-  <ResponseMetadata>
-    <RequestId>1549581b-12b7-11e3-895e-1334aEXAMPLE</RequestId>
-  </ResponseMetadata>
-  <DeleteGlobalClusterResult>
-  <GlobalCluster>
-    {{ cluster.to_xml() }}
-  </GlobalCluster>
-  </DeleteGlobalClusterResult>
-</DeleteGlobalClusterResponse>"""
-
-DESCRIBE_GLOBAL_CLUSTERS_TEMPLATE = """<DescribeGlobalClustersResponse xmlns="http://rds.amazonaws.com/doc/2014-10-31/">
-  <ResponseMetadata>
-    <RequestId>1549581b-12b7-11e3-895e-1334aEXAMPLE</RequestId>
-  </ResponseMetadata>
-  <DescribeGlobalClustersResult>
-    <GlobalClusters>
-{% for cluster in clusters %}
-    <GlobalClusterMember>
-        {{ cluster.to_xml() }}
-        </GlobalClusterMember>
-{% endfor %}
-    </GlobalClusters>
-  </DescribeGlobalClustersResult>
-</DescribeGlobalClustersResponse>"""
-
-REMOVE_FROM_GLOBAL_CLUSTER_TEMPLATE = """<RemoveFromGlobalClusterResponse xmlns="http://rds.amazonaws.com/doc/2014-10-31/">
-  <ResponseMetadata>
-    <RequestId>1549581b-12b7-11e3-895e-1334aEXAMPLE</RequestId>
-  </ResponseMetadata>
-  <RemoveFromGlobalClusterResult>
-  {% if cluster %}
-  <GlobalCluster>
-    {{ cluster.to_xml() }}
-  </GlobalCluster>
-  {% endif %}
-  </RemoveFromGlobalClusterResult>
-</RemoveFromGlobalClusterResponse>"""
-
-
-DEREGISTER_DB_PROXY_TARGET = """<DeregisterDBProxyTargetsResponse xmlns="http://rds.amazonaws.com/doc/2014-10-31/">
-<DeregisterDBProxyTargetsResult>
-</DeregisterDBProxyTargetsResult>
-</DeregisterDBProxyTargetsResponse>"""
-
-
-REGISTER_DB_PROXY_TARGET = """<RegisterDBProxyTargetsResponse xmlns="http://rds.amazonaws.com/doc/2014-10-31/">
-<RegisterDBProxyTargetsResult>
-<DBProxyTargets>
-  {% for target in targets %}
-  <member>
-    <RdsResourceId>{{ target.rds_resource_id }}</RdsResourceId>
-    <Port>5432</Port>
-    <Type>{{ target.type }}</Type>
-    <TargetHealth>
-        <State>REGISTERING</State>
-    </TargetHealth>
-    {% if target.endpoint %}<Endpoint>{{ target.endpoint }}</Endpoint>{% endif %}
-  </member>
-  {% endfor %}
-</DBProxyTargets>
-</RegisterDBProxyTargetsResult>
-</RegisterDBProxyTargetsResponse>"""
-
-
-DESCRIBE_DB_PROXY_TARGETS = """<DescribeDBProxyTargetsResponse xmlns="http://rds.amazonaws.com/doc/2014-10-31/">
-<DescribeDBProxyTargetsResult>
-  <Targets>
-    {% for target in targets %}
-      <member>
-        <RdsResourceId>{{ target.rds_resource_id }}</RdsResourceId>
-        <Port>5432</Port>
-        <Type>{{ target.type }}</Type>
-        <TargetHealth>
-            <State>AVAILABLE</State>
-        </TargetHealth>
-        {% if target.endpoint %}<Endpoint>{{ target.endpoint }}</Endpoint>{% endif %}
-      </member>
-    {% endfor %}
-  </Targets>
-</DescribeDBProxyTargetsResult>
-</DescribeDBProxyTargetsResponse>
-"""
-
-
-DELETE_DB_PROXY_TEMPLATE = """<DeleteDBProxyResponse>
-<DeleteDBProxyResult>
-  <DBProxy>
-    {{ dbproxy.to_xml() }}
-  </DBProxy>
-</DeleteDBProxyResult>
-</DeleteDBProxyResponse>"""
-
-
-DESCRIBE_DB_PROXY_TARGET_GROUPS = """<DescribeDBProxyTargetGroupsResponse>
-<DescribeDBProxyTargetGroupsResult>
-  <TargetGroups>
-  {% for group in groups %}
-    <member>
-      {{ group.to_xml() }}
-    </member>
-  {% endfor %}
-  </TargetGroups>
-</DescribeDBProxyTargetGroupsResult>
-</DescribeDBProxyTargetGroupsResponse>"""
-
-
-MODIFY_DB_PROXY_TARGET_GROUP = """<ModifyDBProxyTargetGroupResponse>
-<ModifyDBProxyTargetGroupResult>
-  <DBProxyTargetGroup>
-    {{ group.to_xml() }}
-  </DBProxyTargetGroup>
-</ModifyDBProxyTargetGroupResult>
-</ModifyDBProxyTargetGroupResponse>"""
diff --git a/moto/rds/serialize.py b/moto/rds/serialize.py
new file mode 100644
index 000000000..b96051486
--- /dev/null
+++ b/moto/rds/serialize.py
@@ -0,0 +1,386 @@
+# mypy: disable-error-code="misc, var-annotated"
+
+from __future__ import annotations
+
+from datetime import datetime
+from typing import Any, Mapping, MutableMapping, Optional, Tuple, Union
+
+import xmltodict
+from botocore.model import (
+    ListShape,
+    NoShapeFoundError,
+    OperationModel,
+    Shape,
+    StructureShape,
+)
+from botocore.utils import parse_to_aware_datetime
+from typing_extensions import TypeAlias
+
+Serialized: TypeAlias = MutableMapping[str, Any]
+
+
+class ErrorShape(StructureShape):
+    pass
+
+
+class ShapeHelpersMixin:
+    @staticmethod
+    def get_serialized_name(shape: Shape, default_name: str) -> str:
+        return shape.serialization.get("name", default_name)
+
+
+class TimestampSerializer:
+    TIMESTAMP_FORMAT_ISO8601 = "iso8601"
+    TIMESTAMP_FORMAT_RFC822 = "rfc822"
+    TIMESTAMP_FORMAT_UNIX = "unixtimestamp"
+
+    ISO8601 = "%Y-%m-%dT%H:%M:%SZ"
+    ISO8601_MICRO = "%Y-%m-%dT%H:%M:%S.%fZ"
+
+    def __init__(self, default_format: str) -> None:
+        self.default_format = default_format
+
+    def serialize(
+        self, serialized: Serialized, value: Any, shape: Shape, key: str
+    ) -> None:
+        timestamp_format = shape.serialization.get(
+            "timestampFormat", self.default_format
+        )
+        serialized_value = self._convert_timestamp_to_str(value, timestamp_format)
+        serialized[key] = serialized_value
+
+    def _timestamp_iso8601(self, value: datetime) -> str:
+        timestamp_format = self.ISO8601
+        if value.microsecond > 0:
+            timestamp_format = self.ISO8601_MICRO
+        return value.strftime(timestamp_format)
+
+    def _convert_timestamp_to_str(
+        self, value: Union[int, str, datetime], timestamp_format: str
+    ) -> str:
+        timestamp_format = timestamp_format.lower()
+        converter = getattr(self, "_timestamp_%s" % timestamp_format)
+        datetime_obj = parse_to_aware_datetime(value)  # type: ignore
+        final_value = converter(datetime_obj)
+        return final_value
+
+
+class Serializer(ShapeHelpersMixin):  # , BaseSerializer):
+    DEFAULT_RESPONSE_CODE = 200
+    DEFAULT_ERROR_RESPONSE_CODE = 400
+    # Clients can change this to a different MutableMapping
+    # (i.e. OrderedDict) if they want.  This is used in the
+    # compliance test to match the hash ordering used in the
+    # tests.
+    # NOTE: This is no longer necessary because dicts post 3.6 are ordered
+    # https://stackoverflow.com/questions/39980323/are-dictionaries-ordered-in-python-3-6
+    MAP_TYPE = dict
+    DEFAULT_ENCODING = "utf-8"
+
+    # From the spec, the default timestamp format if not specified is iso8601.
+    DEFAULT_TIMESTAMP_FORMAT = TimestampSerializer.TIMESTAMP_FORMAT_ISO8601
+
+    def __init__(
+        self,
+        operation_model: OperationModel,
+        context: Optional[dict[str, Any]] = None,
+        value_picker: Any = None,
+        pretty_print: bool = False,
+    ) -> None:
+        self.operation_model = operation_model
+        self.context = context or {"request_id": "request-id"}
+        self.pretty_print = pretty_print
+        self._value_picker = value_picker
+        self._timestamp_serializer = TimestampSerializer(self.DEFAULT_TIMESTAMP_FORMAT)
+
+    def serialize_to_response(
+        self,
+        result: Any,
+    ) -> Mapping[str, Any]:
+        raise NotImplementedError("serialize_to_response")
+
+    def _create_default_response(self) -> Serialized:
+        # Creates a boilerplate default request dict that subclasses
+        # can use as a starting point.
+        serialized = {
+            "status_code": self.DEFAULT_RESPONSE_CODE,
+            "headers": {},
+            # An empty body is represented as an empty string.
+            "body": "",
+        }
+        return serialized
+
+    # Some extra utility methods subclasses can use.
+
+    @staticmethod
+    def _is_error_result(result: object) -> bool:
+        return isinstance(result, Exception)
+
+    def _get_value(self, value: Any, key: str, shape: Shape) -> Any:
+        return self._value_picker(value, key, shape)
+
+
+class ResponseSerializer(Serializer):
+    DEFAULT_TIMESTAMP_FORMAT = TimestampSerializer.TIMESTAMP_FORMAT_ISO8601
+
+    CONTENT_TYPE = "text"
+
+    def _encode_body(self, body: Any) -> str:
+        raise NotImplementedError("_encode_body")
+
+    @staticmethod
+    def _get_error_shape_name(error: Exception) -> str:
+        shape_name = getattr(error, "code", error.__class__.__name__)
+        return shape_name
+
+    def _get_error_shape(
+        self, error: Exception, operation_model: OperationModel
+    ) -> ErrorShape:
+        shape_name = self._get_error_shape_name(error)
+        try:
+            # TODO: there is also an errors array in the operation model,
+            # but I think it only includes the possible errors for that
+            # operation.  Maybe we try that first, then try all shapes?
+            shape = operation_model.service_model.shape_for(shape_name)
+            # We convert to ErrorShape to keep mypy happy...
+            shape = ErrorShape(
+                shape_name,
+                shape._shape_model,  # type: ignore
+                shape._shape_resolver,  # type: ignore
+            )
+        except NoShapeFoundError:
+            generic_error_model = {
+                "exception": True,
+                "type": "structure",
+                "members": {},
+                "error": {
+                    "code": shape_name,
+                },
+            }
+            shape = ErrorShape(shape_name, generic_error_model)
+        return shape
+
+    def _serialize_error(
+        self,
+        serialized: Serialized,
+        error: Exception,
+        operation_model: OperationModel,
+        request_ctx: Mapping[str, Any],
+    ) -> Serialized:
+        shape = self._get_error_shape(error, operation_model)
+        status_code = shape.metadata.get("error", {}).get(
+            "httpStatusCode", self.DEFAULT_ERROR_RESPONSE_CODE
+        )
+        serialized["status_code"] = status_code
+        message = getattr(error, "message", None) or str(error)
+        error_wrapper, error_body = self._get_error_wrapper(
+            operation_model, request_ctx
+        )
+        self._inject_error_metadata(error_body, error, shape, operation_model)
+        if message:
+            error_body["Message"] = message
+        if shape is not None:
+            self._serialize(error_body, error, shape, "")
+        serialized["body"] = error_wrapper
+        self._inject_error_headers(serialized["headers"], shape, operation_model)
+        return serialized
+
+    def _get_error_wrapper(
+        self, operation_model: OperationModel, request_ctx: Mapping[str, Any]
+    ) -> Tuple[Serialized, Serialized]:
+        raise NotImplementedError("_get_error_wrapper")
+
+    def _inject_error_metadata(
+        self,
+        serialized: Serialized,
+        error: Exception,
+        shape: ErrorShape,
+        operation_model: OperationModel,
+    ) -> None:
+        raise NotImplementedError("_inject_error_metadata")
+
+    def _inject_error_headers(
+        self, serialized: Serialized, shape: ErrorShape, operation_model: OperationModel
+    ) -> None:
+        pass
+
+    def _inject_response_metadata(
+        self,
+        serialized: Serialized,
+        operation_model: OperationModel,
+        request_ctx: Mapping[str, Any],
+    ) -> None:
+        raise NotImplementedError("_inject_response_metadata")
+
+    def serialize_to_response(
+        self,
+        result: Any,
+    ) -> Serialized:
+        serialized = self._create_default_response()
+        if self._is_error_result(result):
+            serialized = self._serialize_error(
+                serialized, result, self.operation_model, self.context
+            )
+        else:
+            response_wrapper, result_wrapper = self._get_response_wrapper(
+                self.operation_model, self.context
+            )
+            output_shape = self.operation_model.output_shape
+            if output_shape is not None:
+                self._serialize(result_wrapper, result, output_shape, "")
+
+            root_key = list(response_wrapper.keys())[0]
+            self._inject_response_metadata(
+                response_wrapper[root_key], self.operation_model, self.context
+            )
+
+            serialized["body"] = response_wrapper
+
+        serialized["body"] = self._encode_body(serialized["body"])
+
+        serialized["headers"]["Content-Type"] = self.CONTENT_TYPE
+        return serialized
+
+    def _serialize(
+        self, serialized: Serialized, value: Any, shape: Shape, key: str
+    ) -> None:
+        method = getattr(
+            self, "_serialize_type_%s" % shape.type_name, self._default_serialize
+        )
+        method(serialized, value, shape, key)
+
+    def _serialize_type_structure(
+        self, serialized: Serialized, value: Any, shape: StructureShape, key: str
+    ) -> None:
+        if key:
+            new_serialized = self.MAP_TYPE()
+            serialized[key] = new_serialized
+            serialized = new_serialized
+        for member_key, member_shape in shape.members.items():
+            self._serialize_structure_member(
+                serialized, value, member_shape, member_key
+            )
+
+    def _serialize_structure_member(
+        self, serialized: Serialized, value: Any, shape: Shape, key: str
+    ) -> None:
+        member_value = self._get_value(value, key, shape)
+        if member_value is not None:
+            key_name = self.get_serialized_name(shape, key)
+            self._serialize(serialized, member_value, shape, key_name)
+
+    @staticmethod
+    def _default_serialize(
+        serialized: Serialized, value: Any, _: Shape, key: str
+    ) -> None:
+        serialized[key] = value
+
+    def _serialize_type_timestamp(
+        self, serialized: Serialized, value: Any, shape: Shape, key: str
+    ) -> None:
+        value_wrapper = {}
+        value_key = "timestamp"
+        self._timestamp_serializer.serialize(value_wrapper, value, shape, value_key)
+        self._default_serialize(serialized, value_wrapper[value_key], shape, key)
+
+    def _get_response_wrapper(
+        self, operation_model: OperationModel, request_ctx: Mapping[str, Any]
+    ) -> Tuple[Serialized, Serialized]:
+        raise NotImplementedError("shouldn't get here...")
+
+
+class BaseXMLSerializer(ResponseSerializer):
+    @staticmethod
+    def _serialize_namespace_attribute(
+        serialized: Serialized, operation_model: OperationModel
+    ) -> None:
+        if "xmlNamespace" in operation_model.metadata:
+            namespace = operation_model.metadata["xmlNamespace"]
+            serialized["@xmlns"] = namespace
+
+    def _get_error_wrapper(
+        self, operation_model: OperationModel, request_ctx: Mapping[str, Any]
+    ) -> Tuple[Serialized, Serialized]:
+        serialized_error = self.MAP_TYPE()
+        error_wrapper = {
+            "ErrorResponse": {
+                "Error": serialized_error,
+                "RequestId": request_ctx.get("request_id"),
+            }
+        }
+        self._serialize_namespace_attribute(
+            error_wrapper["ErrorResponse"], operation_model
+        )
+        return error_wrapper, serialized_error
+
+    def _get_response_wrapper(
+        self, operation_model: OperationModel, request_ctx: Mapping[str, Any]
+    ) -> Tuple[Serialized, Serialized]:
+        serialized_result = self.MAP_TYPE()
+        root_key = f"{operation_model.name}Response"
+        response_wrapper = {root_key: {}}
+        output_shape = operation_model.output_shape
+        result_key = None
+        if output_shape is not None:
+            result_key = output_shape.serialization.get("resultWrapper")
+        if result_key is not None:
+            response_wrapper[root_key][result_key] = serialized_result
+        else:
+            response_wrapper[root_key] = serialized_result
+        self._serialize_namespace_attribute(response_wrapper[root_key], operation_model)
+        return response_wrapper, serialized_result
+
+    def _inject_error_metadata(
+        self,
+        serialized: Serialized,
+        error: Exception,
+        shape: ErrorShape,
+        operation_model: OperationModel,
+    ) -> None:
+        sender_fault = shape.metadata.get("error", {}).get("senderFault", True)
+        serialized["Type"] = "Sender" if sender_fault else "Receiver"
+        serialized["Code"] = shape.error_code
+        message = getattr(error, "message", None) or str(error)
+        if message:
+            serialized["Message"] = message
+        if shape is not None:
+            self._serialize(serialized, error, shape, "")
+
+    def _encode_body(self, body: Serialized) -> str:
+        body_encoded = xmltodict.unparse(
+            body,
+            full_document=False,
+            short_empty_elements=True,
+            pretty=self.pretty_print,
+        )
+        return body_encoded
+
+    def _serialize_type_list(
+        self, serialized: Serialized, value: Any, shape: ListShape, key: str
+    ) -> None:
+        list_obj = []
+        items_name = self.get_serialized_name(shape.member, "member")
+        serialized[key] = {items_name: list_obj}
+        for list_item in value:
+            wrapper = {}
+            self._serialize(wrapper, list_item, shape.member, "__current__")
+            list_obj.append(wrapper["__current__"])
+        if not list_obj:
+            serialized[key] = ""
+
+
+class QuerySerializer(BaseXMLSerializer):
+    CONTENT_TYPE = "text/xml"
+
+    def _inject_response_metadata(
+        self,
+        serialized: MutableMapping[str, Any],
+        operation_model: OperationModel,
+        request_ctx: Mapping[str, Any],
+    ) -> None:
+        serialized["ResponseMetadata"] = {"RequestId": request_ctx.get("request_id")}
+
+
+SERIALIZERS = {
+    "query": QuerySerializer,
+}
diff --git a/moto/rds/utils.py b/moto/rds/utils.py
index ebb75d898..924f4c5af 100644
--- a/moto/rds/utils.py
+++ b/moto/rds/utils.py
@@ -1,10 +1,16 @@
+from __future__ import annotations
+
 import copy
 import datetime
 import re
 from collections import OrderedDict, namedtuple
 from enum import Enum
+from functools import lru_cache
 from typing import Any, Dict, List, Optional, Tuple
 
+from botocore import xform_name
+from botocore.loaders import create_loader
+from botocore.model import ServiceModel, Shape
 from botocore.utils import merge_dicts
 
 SECONDS_IN_ONE_DAY = 24 * 60 * 60
@@ -385,3 +391,82 @@ def decode_orderable_db_instance(db: Dict[str, Any]) -> Dict[str, Any]:
         ORDERABLE_DB_INSTANCE_DECODING.get(key, key): value
         for key, value in decoded.items()
     }
+
+
+@lru_cache()
+def get_service_model(service_name: str) -> ServiceModel:
+    loader = create_loader()
+    model = loader.load_service_model(service_name, "service-2")
+    service_model = ServiceModel(model, service_name)
+    return service_model
+
+
+class _Missing:
+    def __repr__(self) -> str:
+        return "<moto.missing>"
+
+
+missing = _Missing()
+
+
+def get_value(obj: Any, key: int | str, default: Any = missing) -> Any:
+    if not hasattr(obj, "__getitem__"):
+        return getattr(obj, str(key), default)
+
+    try:
+        return obj[key]
+    except (KeyError, IndexError, TypeError, AttributeError):
+        return getattr(obj, str(key), default)
+
+
+class ValuePicker:
+    def __init__(self, alias_dict: Dict[str, List[str]]) -> None:
+        self.alias_dict = alias_dict
+
+    def __call__(self, value: Any, key: str, shape: Shape) -> Any:
+        return self._get_value(value, key, shape)
+
+    def _get_value(self, value: Any, key: str, shape: Shape) -> Any:
+        new_value = None
+        possible_keys = self._get_possible_keys(key, value, shape)
+        for key in possible_keys:
+            new_value = get_value(value, key)
+            if new_value is not missing:
+                break
+        if new_value is missing:
+            return None
+        if callable(new_value):
+            new_value = new_value()
+        # Testing if DBInstance.engine was an Engine() instance with a __str__ method
+        if new_value and shape.type_name == "string" and not isinstance(new_value, str):
+            new_value = str(new_value)
+        return new_value
+
+    def _get_possible_keys(self, key: str, obj: Any, shape: Shape) -> List[str]:
+        possible_keys = []
+        # Sometimes the list or structure name differs from the attribute name
+        if shape.type_name in ["list", "structure"]:
+            possible_keys += [shape.name, xform_name(shape.name)]
+        # db_instance_identifier or DBInstanceIdentifier
+        possible_keys += [xform_name(key), key]
+        # Check our alias dict...
+        if key in self.alias_dict:
+            key_aliases = self.alias_dict[key]
+            possible_keys += key_aliases
+        # Translate e.g. DBInstanceIdentifier to identifier if class is DBInstance
+        from moto.rds.models import RDSBaseModel
+
+        obj_is_rds_model = isinstance(obj, RDSBaseModel)
+        obj_is_dto = isinstance(obj, object) and obj.__class__.__name__.endswith("DTO")
+        if obj_is_dto or obj_is_rds_model:  # isinstance(obj, object):
+            # Use alias_dict so DBInstanceDTO resolves to DBInstance
+            default_class_name = obj.__class__.__name__
+            class_name_aliases = self.alias_dict.get(
+                default_class_name, [default_class_name]
+            )
+            class_name = class_name_aliases[0]
+            if class_name in key:
+                short_key = key.replace(class_name, "")
+                possible_keys += [xform_name(short_key), short_key]
+
+        return possible_keys
diff --git a/moto/rds/viewmodels.py b/moto/rds/viewmodels.py
new file mode 100644
index 000000000..975173111
--- /dev/null
+++ b/moto/rds/viewmodels.py
@@ -0,0 +1,441 @@
+# mypy: disable-error-code="misc"
+from __future__ import annotations
+
+from typing import Any, Dict, List, Optional
+
+from .models import (
+    DBCluster,
+    DBClusterSnapshot,
+    DBInstance,
+    DBSecurityGroup,
+    DBSnapshot,
+    DBSubnetGroup,
+    GlobalCluster,
+    OptionGroup,
+    ProxyTarget,
+    ProxyTargetGroup,
+)
+
+# We use this dict to alias AWS model attributes to Moto RDS model attributes
+# This is just temporary.  Eventually we will update the RDS model attributes
+# to match AWS.
+SERIALIZATION_ALIASES = {
+    "CustSubscriptionId": ["subscription_name"],
+    "DatabaseName": ["db_name"],
+    "DbClusterResourceId": ["resource_id"],
+    "DBClusterSnapshotArn": ["snapshot_arn"],
+    "DBClusterSnapshotIdentifier": ["snapshot_id"],
+    "DBInstanceDTO": ["DBInstance"],
+    "DbInstancePort": ["port"],
+    "DBParameterGroupDTO": ["DBParameterGroup"],
+    "DBParameterGroupFamily": ["family"],
+    "DBProxyName": ["proxy_name"],
+    "DBSecurityGroupDTO": ["DBSecurityGroup"],
+    "DBSnapshotArn": ["snapshot_arn"],
+    "DBSnapshotDTO": ["DBSnapshot"],
+    "DBSnapshotIdentifier": ["snapshot_id"],
+    "DBSubnetGroup": ["subnet_group"],
+    "DBSubnetGroupName": ["subnet_name"],
+    "DBSubnetGroupDTO": ["DBSubnetGroup"],
+    "EC2SecurityGroupId": ["id"],
+    "EC2SecurityGroupName": ["name"],
+    "EC2SubnetGroupOwnerId": ["owner_id"],
+    "EventCategoriesList": ["event_categories"],
+    "HttpEndpointEnabled": ["enable_http_endpoint"],
+    "IAMDatabaseAuthenticationEnabled": [
+        "enable_iam_database_authentication",
+        "iam_auth",
+    ],
+    "MultiAZ": ["is_multi_az"],
+    "OptionGroupDTO": ["OptionGroup"],
+    "ReadReplicaSourceDBInstanceIdentifier": ["source_db_identifier"],
+    "S3Bucket": ["s3_bucket_name"],
+    "SourceIdsList": ["source_ids"],
+    "TagList": ["tags"],
+    "TargetGroupArn": ["arn"],
+    "TargetGroupName": ["group_name"],
+}
+
+
+class Engine:
+    def __init__(self, name: str, version: str) -> None:
+        self.name = name
+        self.version = version
+
+    def __str__(self) -> str:
+        return self.name
+
+
+class DBInstanceDTO:
+    def __init__(self, instance: DBInstance) -> None:
+        self.db_instance = instance
+
+    def __getattribute__(self, name: str) -> Any:
+        try:
+            return super().__getattribute__(name)
+        except AttributeError:
+            pass
+        return self.db_instance.__getattribute__(name)
+
+    @property
+    def engine(self) -> Engine:
+        return Engine(self.db_instance.engine, self.db_instance.engine_version)
+
+    @property
+    def master_user_secret(self) -> Optional[Dict[str, Any]]:
+        secret_dict = self.db_instance.master_user_secret()
+        manage_master_user_password = self.db_instance.manage_master_user_password
+        return secret_dict if manage_master_user_password else None
+
+    @property
+    def vpc_security_group_membership_list(self) -> List[Dict[str, Any]]:
+        groups = [
+            {
+                "Status": "active",
+                "VpcSecurityGroupId": id_,
+            }
+            for id_ in self.db_instance.vpc_security_group_ids
+        ]
+        return groups
+
+    @property
+    def db_parameter_group_status_list(self) -> Any:
+        groups = self.db_instance.db_parameter_groups()
+        for group in groups:
+            # this is hideous
+            setattr(group, "ParameterApplyStatus", "in-sync")
+        return groups
+
+    @property
+    def db_security_group_membership_list(self) -> List[Dict[str, Any]]:
+        groups = [
+            {
+                "Status": "active",
+                "DBSecurityGroupName": group,
+            }
+            for group in self.db_instance.security_groups
+        ]
+        return groups
+
+    @property
+    def endpoint(self) -> Dict[str, Any]:
+        return {
+            "Address": self.db_instance.address,
+            "Port": self.db_instance.port,
+        }
+
+    @property
+    def option_group_memberships(self) -> List[Dict[str, Any]]:
+        groups = [
+            {
+                "OptionGroupName": self.db_instance.option_group_name,
+                "Status": "in-sync",
+            }
+        ]
+        return groups
+
+    @property
+    def read_replica_db_instance_identifiers(self) -> List[str]:
+        return [replica for replica in self.db_instance.replicas]
+
+
+class DBProxyTargetGroupDTO:
+    def __init__(self, group: ProxyTargetGroup) -> None:
+        self.group = group
+
+    @property
+    def is_default(self) -> bool:
+        return True
+
+    @property
+    def status(self) -> str:
+        return "available"
+
+    @property
+    def connection_pool_config(self) -> Dict[str, Any]:
+        return {
+            "MaxConnectionsPercent": self.group.max_connections,
+            "MaxIdleConnectionsPercent": self.group.max_idle_connections,
+            "ConnectionBorrowTimeout": self.group.borrow_timeout,
+            "SessionPinningFilters": [
+                filter_ for filter_ in self.group.session_pinning_filters
+            ],
+        }
+
+    def __getattribute__(self, name: str) -> Any:
+        try:
+            return super().__getattribute__(name)
+        except AttributeError:
+            pass
+        return self.group.__getattribute__(name)
+
+
+class DBProxyTargetDTO:
+    def __init__(self, target: ProxyTarget, registering: bool = False) -> None:
+        self.target = target
+        self.registering = registering
+
+    # terrible hack because get_value tries to pull arn and calls .name which isn't there
+    @property
+    def target_arn(self) -> str | None:
+        return None
+
+    @property
+    def role(self) -> None:
+        # We do this because the model right now sets it to "",
+        # which does get serialized...
+        return None
+
+    @property
+    def port(self) -> int:
+        return 5432
+
+    @property
+    def target_health(self) -> Dict[str, Any]:
+        return {
+            "State": "REGISTERING" if self.registering else "AVAILABLE",
+        }
+
+    def __getattribute__(self, name: str) -> Any:
+        try:
+            return super().__getattribute__(name)
+        except AttributeError:
+            pass
+        return self.target.__getattribute__(name)
+
+
+class OptionGroupDTO:
+    def __init__(self, group: OptionGroup) -> None:
+        self.group = group
+
+    @property
+    def options(self) -> List[Dict[str, Any]]:
+        return [
+            {
+                "OptionName": name,
+                "OptionSettings": [
+                    {
+                        "Name": setting.get("Name"),
+                        "Value": setting.get("Value"),
+                    }
+                    for setting in option_settings
+                ],
+            }
+            for name, option_settings in self.group.options.items()
+        ]
+
+    def __getattribute__(self, name: str) -> Any:
+        try:
+            return super().__getattribute__(name)
+        except AttributeError:
+            pass
+        return self.group.__getattribute__(name)
+
+
+class DBSubnetGroupDTO:
+    def __init__(self, subnet_group: DBSubnetGroup) -> None:
+        self.subnet_group = subnet_group
+
+    @property
+    def subnets(self) -> List[Dict[str, Any]]:
+        subnets = [
+            {
+                "SubnetStatus": "Active",
+                "SubnetIdentifier": subnet.id,
+                "SubnetAvailabilityZone": {
+                    "Name": subnet.availability_zone,
+                    "ProvisionedIopsCapable": False,
+                },
+            }
+            for subnet in self.subnet_group.subnets
+        ]
+        return subnets
+
+    def __getattribute__(self, name: str) -> Any:
+        try:
+            return super().__getattribute__(name)
+        except AttributeError:
+            pass
+        return self.subnet_group.__getattribute__(name)
+
+
+class DBSecurityGroupDTO:
+    def __init__(self, security_group: DBSecurityGroup) -> None:
+        self.security_group = security_group
+
+    @property
+    def ip_ranges(self) -> List[Dict[str, Any]]:
+        ranges = [
+            {
+                "CIDRIP": ip_range,
+                "Status": "authorized",
+            }
+            for ip_range in self.security_group.ip_ranges
+        ]
+        return ranges
+
+    def __getattribute__(self, name: str) -> Any:
+        try:
+            return super().__getattribute__(name)
+        except AttributeError:
+            pass
+        return self.security_group.__getattribute__(name)
+
+
+class DBSnapshotDTO:
+    def __init__(self, snapshot: DBSnapshot) -> None:
+        self.db_snapshot = snapshot
+        self.db_instance = snapshot.database
+
+    def __getattribute__(self, name: str) -> Any:
+        try:
+            return super().__getattribute__(name)
+        except AttributeError:
+            pass
+        try:
+            return self.db_snapshot.__getattribute__(name)
+        except AttributeError:
+            pass
+        return self.db_instance.__getattribute__(name)
+
+    @property
+    def dbi_resource_id(self) -> str:
+        return self.db_instance.dbi_resource_id
+
+    @property
+    def engine(self) -> str:
+        return self.db_instance.engine
+
+
+class GlobalClusterDTO:
+    def __init__(self, cluster: GlobalCluster) -> None:
+        self.cluster = cluster
+
+    @property
+    def status(self) -> str:
+        return "available"  # this is hardcoded in GlobalCluster.to_xml
+
+    @property
+    def global_cluster_members(self) -> List[Dict[str, Any]]:
+        readers = [
+            reader.db_cluster_arn
+            for reader in self.cluster.members
+            if not reader.is_writer
+        ]
+        members = [
+            {
+                "DBClusterArn": member.db_cluster_arn,
+                "IsWriter": True if member.is_writer else False,
+                "DBClusterParameterGroupStatus": "in-sync",
+                "PromotionTier": 1,
+                # I don't think this is correct, but current test assert on it being empty for non writers
+                "Readers": [],
+            }
+            for member in self.members
+        ]
+        for member in members:
+            if member["IsWriter"]:
+                member["Readers"] = readers
+            else:
+                member["GlobalWriteForwardingStatus"] = "disabled"
+        return members
+
+    def __getattribute__(self, name: str) -> Any:
+        try:
+            return super().__getattribute__(name)
+        except AttributeError:
+            return self.cluster.__getattribute__(name)
+
+
+class DBClusterDTO:
+    def __init__(self, cluster: DBCluster, creating: bool = False) -> None:
+        self.cluster = cluster
+        self.creating = creating
+
+    def master_user_secret(self) -> Optional[Dict[str, Any]]:
+        secret_dict = self.cluster.master_user_secret()
+        manage_master_user_password = self.cluster.manage_master_user_password
+        return secret_dict if manage_master_user_password else None
+
+    @property
+    def db_cluster_parameter_group(self) -> str:
+        return self.cluster.parameter_group
+
+    @property
+    def status(self) -> str:
+        return "creating" if self.creating else self.cluster.status
+
+    @property
+    def associated_roles(self) -> List[Dict[str, Any]]:
+        return []
+
+    @property
+    def scaling_configuration_info(self) -> Dict[str, Any]:
+        configuration = self.cluster.scaling_configuration or {}
+        info = {
+            "MinCapacity": configuration.get("min_capacity"),
+            "MaxCapacity": configuration.get("max_capacity"),
+            "AutoPause": configuration.get("auto_pause"),
+            "SecondsUntilAutoPause": configuration.get("seconds_until_auto_pause"),
+            "TimeoutAction": configuration.get("timeout_action"),
+            "SecondsBeforeTimeout": configuration.get("seconds_before_timeout"),
+        }
+        return info
+
+    @property
+    def vpc_security_groups(self) -> List[Dict[str, Any]]:
+        groups = [
+            {"VpcSecurityGroupId": sg_id, "Status": "active"}
+            for sg_id in self.cluster.vpc_security_group_ids
+        ]
+        return groups
+
+    @property
+    def domain_memberships(self) -> List[str]:
+        return []
+
+    @property
+    def cross_account_clone(self) -> bool:
+        return False
+
+    @property
+    def global_write_forwarding_requested(self) -> bool:
+        # This does not appear to be in the standard response for any clusters
+        # Docs say it's only for a secondary cluster in aurora global database...
+        return True if self.cluster.global_write_forwarding_requested else False
+
+    @property
+    def db_cluster_members(self) -> List[Dict[str, Any]]:
+        members = [
+            {
+                "DBInstanceIdentifier": member,
+                "IsClusterWriter": True,
+                "DBClusterParameterGroupStatus": "in-sync",
+                "PromotionTier": 1,
+            }
+            for member in self.cluster_members
+        ]
+        return members
+
+    def __getattribute__(self, name: str) -> Any:
+        try:
+            return super().__getattribute__(name)
+        except AttributeError:
+            return self.cluster.__getattribute__(name)
+
+
+class DBClusterSnapshotDTO:
+    def __init__(self, snapshot: DBClusterSnapshot) -> None:
+        self.snapshot = snapshot
+        self.cluster = DBClusterDTO(snapshot.cluster)
+
+    def __getattribute__(self, name: str) -> Any:
+        try:
+            return super().__getattribute__(name)
+        except AttributeError:
+            pass
+        try:
+            return self.snapshot.__getattribute__(name)
+        except AttributeError:
+            pass
+        return self.cluster.__getattribute__(name)


Test patch:
diff --git a/.github/workflows/tests_sdk_ruby.yml b/.github/workflows/tests_sdk_ruby.yml
index c9e3f4289..17c303ace 100644
--- a/.github/workflows/tests_sdk_ruby.yml
+++ b/.github/workflows/tests_sdk_ruby.yml
@@ -13,7 +13,7 @@ jobs:
     steps:
       - uses: actions/checkout@v4
       - name: Set up Ruby ${{ matrix.ruby-version }}
-        uses: ruby/setup-ruby@1287d2b408066abada82d5ad1c63652e758428d9
+        uses: ruby/setup-ruby@2654679fe7f7c29875c669398a8ec0791b8a64a1
         with:
           ruby-version: ${{ matrix.ruby-version }}
       - name: Set up Python 3.8
diff --git a/tests/test_ec2/test_elastic_block_store.py b/tests/test_ec2/test_elastic_block_store.py
index a5636ed2f..376436f46 100644
--- a/tests/test_ec2/test_elastic_block_store.py
+++ b/tests/test_ec2/test_elastic_block_store.py
@@ -1198,3 +1198,17 @@ def test_modify_ebs_default_kms_key_id():
         KmsKeyId=new_default_key["Arn"]
     )["KmsKeyId"]
     assert new_default_ebs_key_arn != original_default_ebs_key_arn
+
+
+@mock_aws
+def test_create_volume_without_size():
+    ec2 = boto3.client("ec2", region_name="us-east-1")
+
+    with pytest.raises(ClientError) as ex:
+        ec2.create_volume(AvailabilityZone="us-east-1a")
+
+    assert ex.value.response["Error"]["Code"] == "MissingParameter"
+    assert (
+        ex.value.response["Error"]["Message"]
+        == "The request must contain the parameter size/snapshot"
+    )