diff --git a/.changelog/30969.txt b/.changelog/30969.txt new file mode 100644 index 00000000000..66efb992b0a --- /dev/null +++ b/.changelog/30969.txt @@ -0,0 +1,11 @@ +```release-note:breaking-change +resource/aws_api_gateway_rest_api: `minimum_compression_size` is now a string type to allow values set via the `body` attribute to be properly computed. +``` + +```release-note:breaking-change +data-source/aws_api_gateway_rest_api: `minimum_compression_size` is now a string type to allow values set via the `body` attribute to be properly computed. +``` + +```release-note:note +resource/aws_api_gateway_rest_api: Update configurations with `minimum_compression_size` set to pass the value as a string. Valid values remain the same. +``` diff --git a/internal/service/apigateway/rest_api.go b/internal/service/apigateway/rest_api.go index 5e24641f2ac..ef768397920 100644 --- a/internal/service/apigateway/rest_api.go +++ b/internal/service/apigateway/rest_api.go @@ -19,6 +19,7 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" "github.com/hashicorp/terraform-provider-aws/internal/conns" "github.com/hashicorp/terraform-provider-aws/internal/errs/sdkdiag" + "github.com/hashicorp/terraform-provider-aws/internal/experimental/nullable" "github.com/hashicorp/terraform-provider-aws/internal/flex" tftags "github.com/hashicorp/terraform-provider-aws/internal/tags" "github.com/hashicorp/terraform-provider-aws/internal/tfresource" @@ -116,10 +117,14 @@ func ResourceRestAPI() *schema.Resource { Optional: true, }, "minimum_compression_size": { - Type: schema.TypeInt, + Type: nullable.TypeNullableInt, Optional: true, - Default: -1, - ValidateFunc: validation.IntBetween(-1, 10485760), + Computed: true, + ValidateFunc: nullable.ValidateTypeStringNullableIntBetween(-1, 10485760), + DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool { + // suppress null trigger when value is already null + return old == "" && new == "-1" + }, }, "name": { Type: schema.TypeString, @@ -196,8 +201,12 @@ func resourceRestAPICreate(ctx context.Context, d *schema.ResourceData, meta int input.EndpointConfiguration = expandEndpointConfiguration(v.([]interface{})) } - if minimumCompressionSize := d.Get("minimum_compression_size").(int); minimumCompressionSize > -1 { - input.MinimumCompressionSize = aws.Int64(int64(minimumCompressionSize)) + if v, ok := d.GetOk("minimum_compression_size"); ok && v.(string) != "" && v.(string) != "-1" { + mcs, err := strconv.Atoi(v.(string)) + if err != nil { + return sdkdiag.AppendErrorf(diags, "converting minimum_compression_size (%s): %s", v, err) + } + input.MinimumCompressionSize = aws.Int64(int64(mcs)) } if v, ok := d.GetOk("policy"); ok { @@ -326,9 +335,9 @@ func resourceRestAPIRead(ctx context.Context, d *schema.ResourceData, meta inter }.String() d.Set("execution_arn", executionARN) if api.MinimumCompressionSize == nil { - d.Set("minimum_compression_size", -1) + d.Set("minimum_compression_size", nil) } else { - d.Set("minimum_compression_size", api.MinimumCompressionSize) + d.Set("minimum_compression_size", strconv.FormatInt(aws.Int64Value(api.MinimumCompressionSize), 10)) } d.Set("name", api.Name) @@ -470,15 +479,15 @@ func resourceRestAPIUpdate(ctx context.Context, d *schema.ResourceData, meta int } if d.HasChange("minimum_compression_size") { - minimumCompressionSize := d.Get("minimum_compression_size").(int) - var value string - if minimumCompressionSize > -1 { - value = strconv.Itoa(minimumCompressionSize) + v := d.Get("minimum_compression_size").(string) + value := aws.String(v) + if v == "-1" { + value = nil } operations = append(operations, &apigateway.PatchOperation{ Op: aws.String(apigateway.OpReplace), Path: aws.String("/minimumCompressionSize"), - Value: aws.String(value), + Value: value, }) } @@ -683,11 +692,15 @@ func resourceRestAPIWithBodyUpdateOperations(d *schema.ResourceData, output *api } } - if v := d.Get("minimum_compression_size").(int); v > -1 && int64(v) != aws.Int64Value(output.MinimumCompressionSize) { + if v, ok := d.GetOk("minimum_compression_size"); ok && v.(string) != strconv.FormatInt(aws.Int64Value(output.MinimumCompressionSize), 10) { + value := aws.String(v.(string)) + if v.(string) == "-1" { + value = nil + } operations = append(operations, &apigateway.PatchOperation{ Op: aws.String(apigateway.OpReplace), Path: aws.String("/minimumCompressionSize"), - Value: aws.String(strconv.Itoa(v)), + Value: value, }) } diff --git a/internal/service/apigateway/rest_api_data_source.go b/internal/service/apigateway/rest_api_data_source.go index 17357688aad..66a99c8bd4d 100644 --- a/internal/service/apigateway/rest_api_data_source.go +++ b/internal/service/apigateway/rest_api_data_source.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "log" + "strconv" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws/arn" @@ -12,6 +13,7 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-provider-aws/internal/conns" "github.com/hashicorp/terraform-provider-aws/internal/errs/sdkdiag" + "github.com/hashicorp/terraform-provider-aws/internal/experimental/nullable" tftags "github.com/hashicorp/terraform-provider-aws/internal/tags" ) @@ -45,7 +47,7 @@ func DataSourceRestAPI() *schema.Resource { Computed: true, }, "minimum_compression_size": { - Type: schema.TypeInt, + Type: nullable.TypeNullableInt, Computed: true, }, "binary_media_types": { @@ -126,9 +128,9 @@ func dataSourceRestAPIRead(ctx context.Context, d *schema.ResourceData, meta int d.Set("binary_media_types", match.BinaryMediaTypes) if match.MinimumCompressionSize == nil { - d.Set("minimum_compression_size", -1) + d.Set("minimum_compression_size", nil) } else { - d.Set("minimum_compression_size", match.MinimumCompressionSize) + d.Set("minimum_compression_size", strconv.FormatInt(aws.Int64Value(match.MinimumCompressionSize), 10)) } if err := d.Set("endpoint_configuration", flattenEndpointConfiguration(match.EndpointConfiguration)); err != nil { diff --git a/internal/service/apigateway/rest_api_data_source_test.go b/internal/service/apigateway/rest_api_data_source_test.go index ed6f51de40c..a14b2353f94 100644 --- a/internal/service/apigateway/rest_api_data_source_test.go +++ b/internal/service/apigateway/rest_api_data_source_test.go @@ -20,10 +20,7 @@ func TestAccAPIGatewayRestAPIDataSource_basic(t *testing.T) { ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, Steps: []resource.TestStep{ { - Config: acctest.ConfigCompose( - testAccRestAPIConfig_name(rName), - testAccRestAPIDataSourceConfig_name(), - ), + Config: testAccRestAPIDataSourceConfig_basic(rName), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttrPair(dataSourceName, "name", resourceName, "name"), resource.TestCheckResourceAttrPair(dataSourceName, "arn", resourceName, "arn"), @@ -53,10 +50,7 @@ func TestAccAPIGatewayRestAPIDataSource_Endpoint_vpcEndpointIDs(t *testing.T) { ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, Steps: []resource.TestStep{ { - Config: acctest.ConfigCompose( - testAccRestAPIConfig_vpcEndpointIDs1(rName), - testAccRestAPIDataSourceConfig_name(), - ), + Config: testAccRestAPIDataSourceConfig_Endpoint_vpcEndpointIDs(rName), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttrPair(dataSourceName, "name", resourceName, "name"), resource.TestCheckResourceAttrPair(dataSourceName, "arn", resourceName, "arn"), @@ -76,10 +70,24 @@ func TestAccAPIGatewayRestAPIDataSource_Endpoint_vpcEndpointIDs(t *testing.T) { }) } -func testAccRestAPIDataSourceConfig_name() string { - return ` +func testAccRestAPIDataSourceConfig_basic(rName string) string { + return acctest.ConfigCompose( + testAccRestAPIConfig_name(rName), + ` +data "aws_api_gateway_rest_api" "test" { + name = aws_api_gateway_rest_api.test.name +} +`, + ) +} + +func testAccRestAPIDataSourceConfig_Endpoint_vpcEndpointIDs(rName string) string { + return acctest.ConfigCompose( + testAccRestAPIConfig_vpcEndpointIDs1(rName), + ` data "aws_api_gateway_rest_api" "test" { name = aws_api_gateway_rest_api.test.name } -` +`, + ) } diff --git a/internal/service/apigateway/rest_api_test.go b/internal/service/apigateway/rest_api_test.go index 660529fc952..60b6c5b80ea 100644 --- a/internal/service/apigateway/rest_api_test.go +++ b/internal/service/apigateway/rest_api_test.go @@ -43,7 +43,6 @@ func TestAccAPIGatewayRestAPI_basic(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "disable_execute_api_endpoint", "false"), resource.TestCheckResourceAttr(resourceName, "endpoint_configuration.#", "1"), acctest.MatchResourceAttrRegionalARN(resourceName, "execution_arn", "execute-api", regexp.MustCompile(`[a-z0-9]+`)), - resource.TestCheckResourceAttr(resourceName, "minimum_compression_size", "-1"), resource.TestCheckResourceAttr(resourceName, "name", rName), resource.TestCheckResourceAttr(resourceName, "parameters.%", "0"), resource.TestMatchResourceAttr(resourceName, "root_resource_id", regexp.MustCompile(`[a-z0-9]+`)), @@ -1036,10 +1035,10 @@ func TestAccAPIGatewayRestAPI_minimumCompressionSize(t *testing.T) { CheckDestroy: testAccCheckRestAPIDestroy(ctx), Steps: []resource.TestStep{ { - Config: testAccRestAPIConfig_minimumCompressionSize(rName, 0), + Config: testAccRestAPIConfig_minimumCompressionSize(rName, "1"), Check: resource.ComposeTestCheckFunc( testAccCheckRestAPIExists(ctx, resourceName, &conf), - resource.TestCheckResourceAttr(resourceName, "minimum_compression_size", "0"), + resource.TestCheckResourceAttr(resourceName, "minimum_compression_size", "1"), ), }, { @@ -1049,14 +1048,14 @@ func TestAccAPIGatewayRestAPI_minimumCompressionSize(t *testing.T) { ImportStateVerifyIgnore: []string{"body", "put_rest_api_mode"}, }, { - Config: testAccRestAPIConfig_minimumCompressionSize(rName, -1), + Config: testAccRestAPIConfig_minimumCompressionSize(rName, "-1"), // -1 removes existing values Check: resource.ComposeTestCheckFunc( testAccCheckRestAPIExists(ctx, resourceName, &conf), - resource.TestCheckResourceAttr(resourceName, "minimum_compression_size", "-1"), + resource.TestCheckResourceAttr(resourceName, "minimum_compression_size", ""), ), }, { - Config: testAccRestAPIConfig_minimumCompressionSize(rName, 5242880), + Config: testAccRestAPIConfig_minimumCompressionSize(rName, "5242880"), Check: resource.ComposeTestCheckFunc( testAccCheckRestAPIExists(ctx, resourceName, &conf), resource.TestCheckResourceAttr(resourceName, "minimum_compression_size", "5242880"), @@ -1079,7 +1078,7 @@ func TestAccAPIGatewayRestAPI_MinimumCompressionSize_overrideBody(t *testing.T) CheckDestroy: testAccCheckRestAPIDestroy(ctx), Steps: []resource.TestStep{ { - Config: testAccRestAPIConfig_minimumCompressionSizeOverrideBody(rName, 1, 5242880), + Config: testAccRestAPIConfig_minimumCompressionSizeOverrideBody(rName, "1", 5242880), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckRestAPIExists(ctx, resourceName, &conf), resource.TestCheckResourceAttr(resourceName, "minimum_compression_size", "1"), @@ -1093,7 +1092,7 @@ func TestAccAPIGatewayRestAPI_MinimumCompressionSize_overrideBody(t *testing.T) }, // Verify updated minimum compression size still overrides { - Config: testAccRestAPIConfig_minimumCompressionSizeOverrideBody(rName, 2, 5242880), + Config: testAccRestAPIConfig_minimumCompressionSizeOverrideBody(rName, "2", 5242880), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckRestAPIExists(ctx, resourceName, &conf), resource.TestCheckResourceAttr(resourceName, "minimum_compression_size", "2"), @@ -1101,7 +1100,7 @@ func TestAccAPIGatewayRestAPI_MinimumCompressionSize_overrideBody(t *testing.T) }, // Verify updated body minimum compression size is still overridden { - Config: testAccRestAPIConfig_minimumCompressionSizeOverrideBody(rName, 2, 1048576), + Config: testAccRestAPIConfig_minimumCompressionSizeOverrideBody(rName, "2", 1048576), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckRestAPIExists(ctx, resourceName, &conf), resource.TestCheckResourceAttr(resourceName, "minimum_compression_size", "2"), @@ -1129,8 +1128,6 @@ func TestAccAPIGatewayRestAPI_MinimumCompressionSize_setByBody(t *testing.T) { testAccCheckRestAPIExists(ctx, resourceName, &conf), resource.TestCheckResourceAttr(resourceName, "minimum_compression_size", "1048576"), ), - // TODO: The attribute type must be changed to NullableTypeInt so it can be Computed properly. - ExpectNonEmptyPlan: true, }, { ResourceName: resourceName, @@ -2414,20 +2411,20 @@ resource "aws_api_gateway_rest_api" "test" { `, rName, bodyDescription) } -func testAccRestAPIConfig_minimumCompressionSize(rName string, minimumCompressionSize int) string { +func testAccRestAPIConfig_minimumCompressionSize(rName string, minimumCompressionSize string) string { return fmt.Sprintf(` resource "aws_api_gateway_rest_api" "test" { - minimum_compression_size = %[2]d name = %[1]q + minimum_compression_size = %[2]q } `, rName, minimumCompressionSize) } -func testAccRestAPIConfig_minimumCompressionSizeOverrideBody(rName string, minimumCompressionSize int, bodyMinimumCompressionSize int) string { +func testAccRestAPIConfig_minimumCompressionSizeOverrideBody(rName string, minimumCompressionSize string, bodyMinimumCompressionSize int) string { return fmt.Sprintf(` resource "aws_api_gateway_rest_api" "test" { - minimum_compression_size = %[2]d name = %[1]q + minimum_compression_size = %[2]q body = jsonencode({ swagger = "2.0" diff --git a/website/docs/r/api_gateway_rest_api.html.markdown b/website/docs/r/api_gateway_rest_api.html.markdown index 3b4c92cd3e5..8b27e8673c1 100644 --- a/website/docs/r/api_gateway_rest_api.html.markdown +++ b/website/docs/r/api_gateway_rest_api.html.markdown @@ -227,7 +227,7 @@ The following arguments are supported: * `description` - (Optional) Description of the REST API. If importing an OpenAPI specification via the `body` argument, this corresponds to the `info.description` field. If the argument value is provided and is different than the OpenAPI value, the argument value will override the OpenAPI value. * `disable_execute_api_endpoint` - (Optional) Whether clients can invoke your API by using the default execute-api endpoint. By default, clients can invoke your API with the default https://{api_id}.execute-api.{region}.amazonaws.com endpoint. To require that clients use a custom domain name to invoke your API, disable the default endpoint. Defaults to `false`. If importing an OpenAPI specification via the `body` argument, this corresponds to the [`x-amazon-apigateway-endpoint-configuration` extension `disableExecuteApiEndpoint` property](https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-swagger-extensions-endpoint-configuration.html). If the argument value is `true` and is different than the OpenAPI value, the argument value will override the OpenAPI value. * `endpoint_configuration` - (Optional) Configuration block defining API endpoint configuration including endpoint type. Defined below. -* `minimum_compression_size` - (Optional) Minimum response size to compress for the REST API. Integer between `-1` and `10485760` (10MB). Setting a value greater than `-1` will enable compression, `-1` disables compression (default). If importing an OpenAPI specification via the `body` argument, this corresponds to the [`x-amazon-apigateway-minimum-compression-size` extension](https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-openapi-minimum-compression-size.html). If the argument value (_except_ `-1`) is provided and is different than the OpenAPI value, the argument value will override the OpenAPI value. +* `minimum_compression_size` - (Optional) Minimum response size to compress for the REST API. String containing an integer value between `-1` and `10485760` (10MB). `-1` will disable an existing compression configuration, and all other values will enable compression with the configured size. New resources can simply omit this argument to disable compression, rather than setting the value to `-1`. If importing an OpenAPI specification via the `body` argument, this corresponds to the [`x-amazon-apigateway-minimum-compression-size` extension](https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-openapi-minimum-compression-size.html). If the argument value is provided and is different than the OpenAPI value, the argument value will override the OpenAPI value. * `name` - (Required) Name of the REST API. If importing an OpenAPI specification via the `body` argument, this corresponds to the `info.title` field. If the argument value is different than the OpenAPI value, the argument value will override the OpenAPI value. * `fail_on_warnings` - (Optional) Whether warnings while API Gateway is creating or updating the resource should return an error or not. Defaults to `false` * `parameters` - (Optional) Map of customizations for importing the specification in the `body` argument. For example, to exclude DocumentationParts from an imported API, set `ignore` equal to `documentation`. Additional documentation, including other parameters such as `basepath`, can be found in the [API Gateway Developer Guide](https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-import-api.html).