diff --git a/.changelog/39159.txt b/.changelog/39159.txt new file mode 100644 index 00000000000..88f09e7f589 --- /dev/null +++ b/.changelog/39159.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +resource/aws_appsync_graphql_api: Add `api_type` and `merged_api_execution_role_arn` arguments +``` diff --git a/internal/service/appsync/appsync_test.go b/internal/service/appsync/appsync_test.go index 2f91b582439..fe80ce44b2d 100644 --- a/internal/service/appsync/appsync_test.go +++ b/internal/service/appsync/appsync_test.go @@ -39,6 +39,7 @@ func TestAccAppSync_serial(t *testing.T) { acctest.CtDisappears: testAccGraphQLAPI_disappears, "tags": testAccGraphQLAPI_tags, "schema": testAccGraphQLAPI_schema, + "apiType": testAccGraphQLAPI_apiType, "authenticationType": testAccGraphQLAPI_authenticationType, "AuthenticationType_apiKey": testAccGraphQLAPI_AuthenticationType_apiKey, "AuthenticationType_awsIAM": testAccGraphQLAPI_AuthenticationType_iam, diff --git a/internal/service/appsync/graphql_api.go b/internal/service/appsync/graphql_api.go index e53e2e60076..fa6b51f329d 100644 --- a/internal/service/appsync/graphql_api.go +++ b/internal/service/appsync/graphql_api.go @@ -131,6 +131,13 @@ func resourceGraphQLAPI() *schema.Resource { }, }, }, + "api_type": { + Type: schema.TypeString, + Optional: true, + ValidateDiagFunc: enum.Validate[awstypes.GraphQLApiType](), + ForceNew: true, + Default: awstypes.GraphQLApiTypeGraphql, + }, names.AttrARN: { Type: schema.TypeString, Computed: true, @@ -217,6 +224,10 @@ func resourceGraphQLAPI() *schema.Resource { }, }, }, + "merged_api_execution_role_arn": { + Type: schema.TypeString, + Optional: true, + }, names.AttrName: { Type: schema.TypeString, Required: true, @@ -329,6 +340,10 @@ func resourceGraphQLAPICreate(ctx context.Context, d *schema.ResourceData, meta input.AdditionalAuthenticationProviders = expandAdditionalAuthenticationProviders(v.([]interface{}), meta.(*conns.AWSClient).Region) } + if v, ok := d.GetOk("api_type"); ok { + input.ApiType = awstypes.GraphQLApiType(v.(string)) + } + if v, ok := d.GetOk("enhanced_metrics_config"); ok { input.EnhancedMetricsConfig = expandEnhancedMetricsConfig(v.([]interface{})) } @@ -345,6 +360,10 @@ func resourceGraphQLAPICreate(ctx context.Context, d *schema.ResourceData, meta input.LogConfig = expandLogConfig(v.([]interface{})) } + if v, ok := d.GetOk("merged_api_execution_role_arn"); ok { + input.MergedApiExecutionRoleArn = aws.String(v.(string)) + } + if v, ok := d.GetOk("openid_connect_config"); ok { input.OpenIDConnectConfig = expandOpenIDConnectConfig(v.([]interface{})) } @@ -405,6 +424,7 @@ func resourceGraphQLAPIRead(ctx context.Context, d *schema.ResourceData, meta in if err := d.Set("additional_authentication_provider", flattenAdditionalAuthenticationProviders(api.AdditionalAuthenticationProviders)); err != nil { return sdkdiag.AppendErrorf(diags, "setting additional_authentication_provider: %s", err) } + d.Set("api_type", api.ApiType) d.Set(names.AttrARN, api.Arn) d.Set("authentication_type", api.AuthenticationType) if err := d.Set("enhanced_metrics_config", flattenEnhancedMetricsConfig(api.EnhancedMetricsConfig)); err != nil { @@ -417,6 +437,7 @@ func resourceGraphQLAPIRead(ctx context.Context, d *schema.ResourceData, meta in if err := d.Set("log_config", flattenLogConfig(api.LogConfig)); err != nil { return sdkdiag.AppendErrorf(diags, "setting log_config: %s", err) } + d.Set("merged_api_execution_role_arn", api.MergedApiExecutionRoleArn) d.Set(names.AttrName, api.Name) if err := d.Set("openid_connect_config", flattenOpenIDConnectConfig(api.OpenIDConnectConfig)); err != nil { return sdkdiag.AppendErrorf(diags, "setting openid_connect_config: %s", err) @@ -466,6 +487,10 @@ func resourceGraphQLAPIUpdate(ctx context.Context, d *schema.ResourceData, meta input.LogConfig = expandLogConfig(v.([]interface{})) } + if v, ok := d.GetOk("merged_api_execution_role_arn"); ok { + input.MergedApiExecutionRoleArn = aws.String(v.(string)) + } + if v, ok := d.GetOk("openid_connect_config"); ok { input.OpenIDConnectConfig = expandOpenIDConnectConfig(v.([]interface{})) } diff --git a/internal/service/appsync/graphql_api_test.go b/internal/service/appsync/graphql_api_test.go index 8f8088d5874..30b2e8a2d8a 100644 --- a/internal/service/appsync/graphql_api_test.go +++ b/internal/service/appsync/graphql_api_test.go @@ -1403,6 +1403,35 @@ func testAccCheckGraphQLAPITypeExists(ctx context.Context, n, typeName string) r } } +func testAccGraphQLAPI_apiType(t *testing.T) { + ctx := acctest.Context(t) + var api1 awstypes.GraphqlApi + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_appsync_graphql_api.test" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t); acctest.PreCheckPartitionHasService(t, names.AppSyncEndpointID) }, + ErrorCheck: acctest.ErrorCheck(t, names.AppSyncServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckGraphQLAPIDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccGraphQLAPIConfig_apiType(rName, string(awstypes.GraphQLApiTypeMerged)), + Check: resource.ComposeTestCheckFunc( + testAccCheckGraphQLAPIExists(ctx, resourceName, &api1), + resource.TestCheckResourceAttr(resourceName, names.AttrName, rName), + resource.TestCheckResourceAttr(resourceName, "api_type", string(awstypes.GraphQLApiTypeMerged)), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + func testAccGraphQLAPIConfig_authenticationType(rName, authenticationType string) string { return fmt.Sprintf(` resource "aws_appsync_graphql_api" "test" { @@ -1882,3 +1911,46 @@ resource "aws_appsync_graphql_api" "test" { } `, rName, resolverCountLimit) } + +func testAccGraphQLAPIConfig_apiType(rName, apiType string) string { + return fmt.Sprintf(` +resource "aws_iam_role" "test" { + assume_role_policy = data.aws_iam_policy_document.test.json + name_prefix = %[1]q +} + +data "aws_caller_identity" "current" {} + +data "aws_partition" "current" {} + +data "aws_region" "current" {} + +data "aws_iam_policy_document" "test" { + statement { + actions = ["sts:AssumeRole"] + principals { + identifiers = ["appsync.amazonaws.com"] + type = "Service" + } + condition { + test = "StringEquals" + values = [data.aws_caller_identity.current.account_id] + variable = "aws:SourceAccount" + } + + condition { + test = "ArnLike" + values = ["arn:${data.aws_partition.current.partition}:appsync:${data.aws_region.current.name}:${data.aws_caller_identity.current.account_id}::apis/*"] + variable = "aws:SourceArn" + } + } +} + +resource "aws_appsync_graphql_api" "test" { + authentication_type = "API_KEY" + name = %[1]q + api_type = %[2]q + merged_api_execution_role_arn = aws_iam_role.test.arn +} +`, rName, apiType) +} diff --git a/website/docs/r/appsync_graphql_api.html.markdown b/website/docs/r/appsync_graphql_api.html.markdown index 9928be40255..0ad312002c2 100644 --- a/website/docs/r/appsync_graphql_api.html.markdown +++ b/website/docs/r/appsync_graphql_api.html.markdown @@ -215,15 +215,17 @@ resource "aws_appsync_graphql_api" "example" { The following arguments are required: * `authentication_type` - (Required) Authentication type. Valid values: `API_KEY`, `AWS_IAM`, `AMAZON_COGNITO_USER_POOLS`, `OPENID_CONNECT`, `AWS_LAMBDA` -* `name` - (Required) User-supplied name for the GraphSQL API. +* `name` - (Required) User-supplied name for the GraphQL API. The following arguments are optional: -* `additional_authentication_provider` - (Optional) One or more additional authentication providers for the GraphSQL API. See [`additional_authentication_provider` Block](#additional_authentication_provider-block) for details. +* `additional_authentication_provider` - (Optional) One or more additional authentication providers for the GraphQL API. See [`additional_authentication_provider` Block](#additional_authentication_provider-block) for details. +* `api_type` - (Optional) API type. Valid values are `GRAPHQL` or `MERGED`. A `MERGED` type requires `merged_api_execution_role_arn` to be set. * `enhanced_metrics_config` - (Optional) Enables and controls the enhanced metrics feature. See [`enhanced_metrics_config` Block](#enhanced_metrics_config-block) for details. * `introspection_config` - (Optional) Sets the value of the GraphQL API to enable (`ENABLED`) or disable (`DISABLED`) introspection. If no value is provided, the introspection configuration will be set to ENABLED by default. This field will produce an error if the operation attempts to use the introspection feature while this field is disabled. For more information about introspection, see [GraphQL introspection](https://graphql.org/learn/introspection/). * `lambda_authorizer_config` - (Optional) Nested argument containing Lambda authorizer configuration. See [`lambda_authorizer_config` Block](#lambda_authorizer_config-block) for details. * `log_config` - (Optional) Nested argument containing logging configuration. See [`log_config` Block](#log_config-block) for details. +* `merged_api_execution_role_arn` - (Optional) ARN of the execution role when `api_type` is set to `MERGED`. * `openid_connect_config` - (Optional) Nested argument containing OpenID Connect configuration. See [`openid_connect_config` Block](#openid_connect_config-block) for details. * `query_depth_limit` - (Optional) The maximum depth a query can have in a single request. Depth refers to the amount of nested levels allowed in the body of query. The default value is `0` (or unspecified), which indicates there's no depth limit. If you set a limit, it can be between `1` and `75` nested levels. This field will produce a limit error if the operation falls out of bounds. @@ -292,7 +294,7 @@ This resource exports the following attributes in addition to the arguments abov * `id` - API ID * `arn` - ARN * `tags_all` - Map of tags assigned to the resource, including those inherited from the provider [`default_tags` configuration block](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#default_tags-configuration-block). -* `uris` - Map of URIs associated with the APIE.g., `uris["GRAPHQL"] = https://ID.appsync-api.REGION.amazonaws.com/graphql` +* `uris` - Map of URIs associated with the API E.g., `uris["GRAPHQL"] = https://ID.appsync-api.REGION.amazonaws.com/graphql` ## Import