The aws:appsync/graphQLApi:GraphQLApi resource, part of the Pulumi AWS provider, defines an AppSync GraphQL API: its authentication methods, schema, and operational controls. This guide focuses on three capabilities: authentication configuration (API keys, IAM, Cognito, Lambda), schema definition, and logging and query complexity limits.
GraphQL APIs reference Cognito User Pools, Lambda authorizers, and IAM roles for authentication. Data sources and resolvers are configured separately via companion resources. The examples are intentionally small. Combine them with your own data sources, resolvers, and monitoring infrastructure.
Authenticate with API keys for public access
Many APIs start with API key authentication for simple, public-facing endpoints where you control access through key rotation rather than user identity.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
const example = new aws.appsync.GraphQLApi("example", {
authenticationType: "API_KEY",
name: "example",
});
import pulumi
import pulumi_aws as aws
example = aws.appsync.GraphQLApi("example",
authentication_type="API_KEY",
name="example")
package main
import (
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/appsync"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_, err := appsync.NewGraphQLApi(ctx, "example", &appsync.GraphQLApiArgs{
AuthenticationType: pulumi.String("API_KEY"),
Name: pulumi.String("example"),
})
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;
return await Deployment.RunAsync(() =>
{
var example = new Aws.AppSync.GraphQLApi("example", new()
{
AuthenticationType = "API_KEY",
Name = "example",
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.appsync.GraphQLApi;
import com.pulumi.aws.appsync.GraphQLApiArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
public class App {
public static void main(String[] args) {
Pulumi.run(App::stack);
}
public static void stack(Context ctx) {
var example = new GraphQLApi("example", GraphQLApiArgs.builder()
.authenticationType("API_KEY")
.name("example")
.build());
}
}
resources:
example:
type: aws:appsync:GraphQLApi
properties:
authenticationType: API_KEY
name: example
The authenticationType property determines how clients prove their identity. API_KEY authentication generates a key that clients include in request headers. AppSync rotates keys automatically based on your expiration settings.
Authenticate with IAM for AWS service integration
Applications running on AWS often use IAM authentication to leverage existing roles and policies, avoiding separate credential management.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
const example = new aws.appsync.GraphQLApi("example", {
authenticationType: "AWS_IAM",
name: "example",
});
import pulumi
import pulumi_aws as aws
example = aws.appsync.GraphQLApi("example",
authentication_type="AWS_IAM",
name="example")
package main
import (
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/appsync"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_, err := appsync.NewGraphQLApi(ctx, "example", &appsync.GraphQLApiArgs{
AuthenticationType: pulumi.String("AWS_IAM"),
Name: pulumi.String("example"),
})
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;
return await Deployment.RunAsync(() =>
{
var example = new Aws.AppSync.GraphQLApi("example", new()
{
AuthenticationType = "AWS_IAM",
Name = "example",
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.appsync.GraphQLApi;
import com.pulumi.aws.appsync.GraphQLApiArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
public class App {
public static void main(String[] args) {
Pulumi.run(App::stack);
}
public static void stack(Context ctx) {
var example = new GraphQLApi("example", GraphQLApiArgs.builder()
.authenticationType("AWS_IAM")
.name("example")
.build());
}
}
resources:
example:
type: aws:appsync:GraphQLApi
properties:
authenticationType: AWS_IAM
name: example
When authenticationType is AWS_IAM, clients sign requests using AWS Signature Version 4. This integrates with IAM roles attached to Lambda functions, EC2 instances, or other AWS services, eliminating the need to manage separate credentials.
Authenticate users through Cognito User Pools
User-facing applications typically need to authenticate end users through identity providers. Cognito User Pools provide user registration, sign-in, and access control.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
const example = new aws.appsync.GraphQLApi("example", {
authenticationType: "AMAZON_COGNITO_USER_POOLS",
name: "example",
userPoolConfig: {
awsRegion: current.region,
defaultAction: "DENY",
userPoolId: exampleAwsCognitoUserPool.id,
},
});
import pulumi
import pulumi_aws as aws
example = aws.appsync.GraphQLApi("example",
authentication_type="AMAZON_COGNITO_USER_POOLS",
name="example",
user_pool_config={
"aws_region": current["region"],
"default_action": "DENY",
"user_pool_id": example_aws_cognito_user_pool["id"],
})
package main
import (
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/appsync"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_, err := appsync.NewGraphQLApi(ctx, "example", &appsync.GraphQLApiArgs{
AuthenticationType: pulumi.String("AMAZON_COGNITO_USER_POOLS"),
Name: pulumi.String("example"),
UserPoolConfig: &appsync.GraphQLApiUserPoolConfigArgs{
AwsRegion: pulumi.Any(current.Region),
DefaultAction: pulumi.String("DENY"),
UserPoolId: pulumi.Any(exampleAwsCognitoUserPool.Id),
},
})
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;
return await Deployment.RunAsync(() =>
{
var example = new Aws.AppSync.GraphQLApi("example", new()
{
AuthenticationType = "AMAZON_COGNITO_USER_POOLS",
Name = "example",
UserPoolConfig = new Aws.AppSync.Inputs.GraphQLApiUserPoolConfigArgs
{
AwsRegion = current.Region,
DefaultAction = "DENY",
UserPoolId = exampleAwsCognitoUserPool.Id,
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.appsync.GraphQLApi;
import com.pulumi.aws.appsync.GraphQLApiArgs;
import com.pulumi.aws.appsync.inputs.GraphQLApiUserPoolConfigArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
public class App {
public static void main(String[] args) {
Pulumi.run(App::stack);
}
public static void stack(Context ctx) {
var example = new GraphQLApi("example", GraphQLApiArgs.builder()
.authenticationType("AMAZON_COGNITO_USER_POOLS")
.name("example")
.userPoolConfig(GraphQLApiUserPoolConfigArgs.builder()
.awsRegion(current.region())
.defaultAction("DENY")
.userPoolId(exampleAwsCognitoUserPool.id())
.build())
.build());
}
}
resources:
example:
type: aws:appsync:GraphQLApi
properties:
authenticationType: AMAZON_COGNITO_USER_POOLS
name: example
userPoolConfig:
awsRegion: ${current.region}
defaultAction: DENY
userPoolId: ${exampleAwsCognitoUserPool.id}
The userPoolConfig block connects your API to a Cognito User Pool. The defaultAction property controls what happens when a user’s token is valid but they lack explicit permissions; DENY requires explicit authorization rules. Clients include Cognito JWT tokens in request headers.
Implement custom authorization with Lambda
Complex authorization logic that doesn’t fit standard identity providers can be implemented in Lambda functions, giving you full control over access decisions.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
const example = new aws.appsync.GraphQLApi("example", {
authenticationType: "AWS_LAMBDA",
name: "example",
lambdaAuthorizerConfig: {
authorizerUri: "arn:aws:lambda:us-east-1:123456789012:function:custom_lambda_authorizer",
},
});
const appsyncLambdaAuthorizer = new aws.lambda.Permission("appsync_lambda_authorizer", {
statementId: "appsync_lambda_authorizer",
action: "lambda:InvokeFunction",
"function": "custom_lambda_authorizer",
principal: "appsync.amazonaws.com",
sourceArn: example.arn,
});
import pulumi
import pulumi_aws as aws
example = aws.appsync.GraphQLApi("example",
authentication_type="AWS_LAMBDA",
name="example",
lambda_authorizer_config={
"authorizer_uri": "arn:aws:lambda:us-east-1:123456789012:function:custom_lambda_authorizer",
})
appsync_lambda_authorizer = aws.lambda_.Permission("appsync_lambda_authorizer",
statement_id="appsync_lambda_authorizer",
action="lambda:InvokeFunction",
function="custom_lambda_authorizer",
principal="appsync.amazonaws.com",
source_arn=example.arn)
package main
import (
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/appsync"
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/lambda"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
example, err := appsync.NewGraphQLApi(ctx, "example", &appsync.GraphQLApiArgs{
AuthenticationType: pulumi.String("AWS_LAMBDA"),
Name: pulumi.String("example"),
LambdaAuthorizerConfig: &appsync.GraphQLApiLambdaAuthorizerConfigArgs{
AuthorizerUri: pulumi.String("arn:aws:lambda:us-east-1:123456789012:function:custom_lambda_authorizer"),
},
})
if err != nil {
return err
}
_, err = lambda.NewPermission(ctx, "appsync_lambda_authorizer", &lambda.PermissionArgs{
StatementId: pulumi.String("appsync_lambda_authorizer"),
Action: pulumi.String("lambda:InvokeFunction"),
Function: pulumi.Any("custom_lambda_authorizer"),
Principal: pulumi.String("appsync.amazonaws.com"),
SourceArn: example.Arn,
})
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;
return await Deployment.RunAsync(() =>
{
var example = new Aws.AppSync.GraphQLApi("example", new()
{
AuthenticationType = "AWS_LAMBDA",
Name = "example",
LambdaAuthorizerConfig = new Aws.AppSync.Inputs.GraphQLApiLambdaAuthorizerConfigArgs
{
AuthorizerUri = "arn:aws:lambda:us-east-1:123456789012:function:custom_lambda_authorizer",
},
});
var appsyncLambdaAuthorizer = new Aws.Lambda.Permission("appsync_lambda_authorizer", new()
{
StatementId = "appsync_lambda_authorizer",
Action = "lambda:InvokeFunction",
Function = "custom_lambda_authorizer",
Principal = "appsync.amazonaws.com",
SourceArn = example.Arn,
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.appsync.GraphQLApi;
import com.pulumi.aws.appsync.GraphQLApiArgs;
import com.pulumi.aws.appsync.inputs.GraphQLApiLambdaAuthorizerConfigArgs;
import com.pulumi.aws.lambda.Permission;
import com.pulumi.aws.lambda.PermissionArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
public class App {
public static void main(String[] args) {
Pulumi.run(App::stack);
}
public static void stack(Context ctx) {
var example = new GraphQLApi("example", GraphQLApiArgs.builder()
.authenticationType("AWS_LAMBDA")
.name("example")
.lambdaAuthorizerConfig(GraphQLApiLambdaAuthorizerConfigArgs.builder()
.authorizerUri("arn:aws:lambda:us-east-1:123456789012:function:custom_lambda_authorizer")
.build())
.build());
var appsyncLambdaAuthorizer = new Permission("appsyncLambdaAuthorizer", PermissionArgs.builder()
.statementId("appsync_lambda_authorizer")
.action("lambda:InvokeFunction")
.function("custom_lambda_authorizer")
.principal("appsync.amazonaws.com")
.sourceArn(example.arn())
.build());
}
}
resources:
example:
type: aws:appsync:GraphQLApi
properties:
authenticationType: AWS_LAMBDA
name: example
lambdaAuthorizerConfig:
authorizerUri: arn:aws:lambda:us-east-1:123456789012:function:custom_lambda_authorizer
appsyncLambdaAuthorizer:
type: aws:lambda:Permission
name: appsync_lambda_authorizer
properties:
statementId: appsync_lambda_authorizer
action: lambda:InvokeFunction
function: custom_lambda_authorizer
principal: appsync.amazonaws.com
sourceArn: ${example.arn}
When authenticationType is AWS_LAMBDA, AppSync invokes your Lambda function for each request. The authorizerUri points to the function that evaluates the request and returns an authorization decision. The Lambda permission grants AppSync the ability to invoke your function.
Support multiple authentication methods simultaneously
APIs serving different client types often need to accept multiple authentication methods, such as API keys for public clients and IAM for internal services.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
const example = new aws.appsync.GraphQLApi("example", {
authenticationType: "API_KEY",
name: "example",
additionalAuthenticationProviders: [{
authenticationType: "AWS_IAM",
}],
});
import pulumi
import pulumi_aws as aws
example = aws.appsync.GraphQLApi("example",
authentication_type="API_KEY",
name="example",
additional_authentication_providers=[{
"authentication_type": "AWS_IAM",
}])
package main
import (
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/appsync"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_, err := appsync.NewGraphQLApi(ctx, "example", &appsync.GraphQLApiArgs{
AuthenticationType: pulumi.String("API_KEY"),
Name: pulumi.String("example"),
AdditionalAuthenticationProviders: appsync.GraphQLApiAdditionalAuthenticationProviderArray{
&appsync.GraphQLApiAdditionalAuthenticationProviderArgs{
AuthenticationType: pulumi.String("AWS_IAM"),
},
},
})
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;
return await Deployment.RunAsync(() =>
{
var example = new Aws.AppSync.GraphQLApi("example", new()
{
AuthenticationType = "API_KEY",
Name = "example",
AdditionalAuthenticationProviders = new[]
{
new Aws.AppSync.Inputs.GraphQLApiAdditionalAuthenticationProviderArgs
{
AuthenticationType = "AWS_IAM",
},
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.appsync.GraphQLApi;
import com.pulumi.aws.appsync.GraphQLApiArgs;
import com.pulumi.aws.appsync.inputs.GraphQLApiAdditionalAuthenticationProviderArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
public class App {
public static void main(String[] args) {
Pulumi.run(App::stack);
}
public static void stack(Context ctx) {
var example = new GraphQLApi("example", GraphQLApiArgs.builder()
.authenticationType("API_KEY")
.name("example")
.additionalAuthenticationProviders(GraphQLApiAdditionalAuthenticationProviderArgs.builder()
.authenticationType("AWS_IAM")
.build())
.build());
}
}
resources:
example:
type: aws:appsync:GraphQLApi
properties:
authenticationType: API_KEY
name: example
additionalAuthenticationProviders:
- authenticationType: AWS_IAM
The additionalAuthenticationProviders array lets you specify secondary authentication methods beyond the primary authenticationType. Clients choose which method to use by including the appropriate credentials in their requests. This enables public API access via keys while allowing internal services to use IAM.
Define the GraphQL schema inline
GraphQL APIs require a schema that defines types, queries, and mutations. You can provide this schema directly in the API resource.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
const example = new aws.appsync.GraphQLApi("example", {
authenticationType: "AWS_IAM",
name: "example",
schema: `schema {
\\tquery: Query
}
type Query {
test: Int
}
`,
});
import pulumi
import pulumi_aws as aws
example = aws.appsync.GraphQLApi("example",
authentication_type="AWS_IAM",
name="example",
schema="""schema {
\tquery: Query
}
type Query {
test: Int
}
""")
package main
import (
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/appsync"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_, err := appsync.NewGraphQLApi(ctx, "example", &appsync.GraphQLApiArgs{
AuthenticationType: pulumi.String("AWS_IAM"),
Name: pulumi.String("example"),
Schema: pulumi.String(`schema {
\tquery: Query
}
type Query {
test: Int
}
`),
})
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;
return await Deployment.RunAsync(() =>
{
var example = new Aws.AppSync.GraphQLApi("example", new()
{
AuthenticationType = "AWS_IAM",
Name = "example",
Schema = @"schema {
\tquery: Query
}
type Query {
test: Int
}
",
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.appsync.GraphQLApi;
import com.pulumi.aws.appsync.GraphQLApiArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
public class App {
public static void main(String[] args) {
Pulumi.run(App::stack);
}
public static void stack(Context ctx) {
var example = new GraphQLApi("example", GraphQLApiArgs.builder()
.authenticationType("AWS_IAM")
.name("example")
.schema("""
schema {
\tquery: Query
}
type Query {
test: Int
}
""")
.build());
}
}
resources:
example:
type: aws:appsync:GraphQLApi
properties:
authenticationType: AWS_IAM
name: example
schema: |
schema {
\tquery: Query
}
type Query {
test: Int
}
The schema property accepts GraphQL Schema Definition Language (SDL). This defines your type system, queries, mutations, and subscriptions. AppSync validates incoming requests against this schema. Note that Pulumi cannot detect drift in schema configuration.
Send API logs to CloudWatch
Production APIs need observability into request patterns, errors, and performance. CloudWatch Logs provides centralized logging for debugging and monitoring.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
const assumeRole = aws.iam.getPolicyDocument({
statements: [{
effect: "Allow",
principals: [{
type: "Service",
identifiers: ["appsync.amazonaws.com"],
}],
actions: ["sts:AssumeRole"],
}],
});
const example = new aws.iam.Role("example", {
name: "example",
assumeRolePolicy: assumeRole.then(assumeRole => assumeRole.json),
});
const exampleRolePolicyAttachment = new aws.iam.RolePolicyAttachment("example", {
policyArn: "arn:aws:iam::aws:policy/service-role/AWSAppSyncPushToCloudWatchLogs",
role: example.name,
});
const exampleGraphQLApi = new aws.appsync.GraphQLApi("example", {logConfig: {
cloudwatchLogsRoleArn: example.arn,
fieldLogLevel: "ERROR",
}});
import pulumi
import pulumi_aws as aws
assume_role = aws.iam.get_policy_document(statements=[{
"effect": "Allow",
"principals": [{
"type": "Service",
"identifiers": ["appsync.amazonaws.com"],
}],
"actions": ["sts:AssumeRole"],
}])
example = aws.iam.Role("example",
name="example",
assume_role_policy=assume_role.json)
example_role_policy_attachment = aws.iam.RolePolicyAttachment("example",
policy_arn="arn:aws:iam::aws:policy/service-role/AWSAppSyncPushToCloudWatchLogs",
role=example.name)
example_graph_ql_api = aws.appsync.GraphQLApi("example", log_config={
"cloudwatch_logs_role_arn": example.arn,
"field_log_level": "ERROR",
})
package main
import (
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/appsync"
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/iam"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
assumeRole, err := iam.GetPolicyDocument(ctx, &iam.GetPolicyDocumentArgs{
Statements: []iam.GetPolicyDocumentStatement{
{
Effect: pulumi.StringRef("Allow"),
Principals: []iam.GetPolicyDocumentStatementPrincipal{
{
Type: "Service",
Identifiers: []string{
"appsync.amazonaws.com",
},
},
},
Actions: []string{
"sts:AssumeRole",
},
},
},
}, nil)
if err != nil {
return err
}
example, err := iam.NewRole(ctx, "example", &iam.RoleArgs{
Name: pulumi.String("example"),
AssumeRolePolicy: pulumi.String(assumeRole.Json),
})
if err != nil {
return err
}
_, err = iam.NewRolePolicyAttachment(ctx, "example", &iam.RolePolicyAttachmentArgs{
PolicyArn: pulumi.String("arn:aws:iam::aws:policy/service-role/AWSAppSyncPushToCloudWatchLogs"),
Role: example.Name,
})
if err != nil {
return err
}
_, err = appsync.NewGraphQLApi(ctx, "example", &appsync.GraphQLApiArgs{
LogConfig: &appsync.GraphQLApiLogConfigArgs{
CloudwatchLogsRoleArn: example.Arn,
FieldLogLevel: pulumi.String("ERROR"),
},
})
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;
return await Deployment.RunAsync(() =>
{
var assumeRole = Aws.Iam.GetPolicyDocument.Invoke(new()
{
Statements = new[]
{
new Aws.Iam.Inputs.GetPolicyDocumentStatementInputArgs
{
Effect = "Allow",
Principals = new[]
{
new Aws.Iam.Inputs.GetPolicyDocumentStatementPrincipalInputArgs
{
Type = "Service",
Identifiers = new[]
{
"appsync.amazonaws.com",
},
},
},
Actions = new[]
{
"sts:AssumeRole",
},
},
},
});
var example = new Aws.Iam.Role("example", new()
{
Name = "example",
AssumeRolePolicy = assumeRole.Apply(getPolicyDocumentResult => getPolicyDocumentResult.Json),
});
var exampleRolePolicyAttachment = new Aws.Iam.RolePolicyAttachment("example", new()
{
PolicyArn = "arn:aws:iam::aws:policy/service-role/AWSAppSyncPushToCloudWatchLogs",
Role = example.Name,
});
var exampleGraphQLApi = new Aws.AppSync.GraphQLApi("example", new()
{
LogConfig = new Aws.AppSync.Inputs.GraphQLApiLogConfigArgs
{
CloudwatchLogsRoleArn = example.Arn,
FieldLogLevel = "ERROR",
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.iam.IamFunctions;
import com.pulumi.aws.iam.inputs.GetPolicyDocumentArgs;
import com.pulumi.aws.iam.Role;
import com.pulumi.aws.iam.RoleArgs;
import com.pulumi.aws.iam.RolePolicyAttachment;
import com.pulumi.aws.iam.RolePolicyAttachmentArgs;
import com.pulumi.aws.appsync.GraphQLApi;
import com.pulumi.aws.appsync.GraphQLApiArgs;
import com.pulumi.aws.appsync.inputs.GraphQLApiLogConfigArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
public class App {
public static void main(String[] args) {
Pulumi.run(App::stack);
}
public static void stack(Context ctx) {
final var assumeRole = IamFunctions.getPolicyDocument(GetPolicyDocumentArgs.builder()
.statements(GetPolicyDocumentStatementArgs.builder()
.effect("Allow")
.principals(GetPolicyDocumentStatementPrincipalArgs.builder()
.type("Service")
.identifiers("appsync.amazonaws.com")
.build())
.actions("sts:AssumeRole")
.build())
.build());
var example = new Role("example", RoleArgs.builder()
.name("example")
.assumeRolePolicy(assumeRole.json())
.build());
var exampleRolePolicyAttachment = new RolePolicyAttachment("exampleRolePolicyAttachment", RolePolicyAttachmentArgs.builder()
.policyArn("arn:aws:iam::aws:policy/service-role/AWSAppSyncPushToCloudWatchLogs")
.role(example.name())
.build());
var exampleGraphQLApi = new GraphQLApi("exampleGraphQLApi", GraphQLApiArgs.builder()
.logConfig(GraphQLApiLogConfigArgs.builder()
.cloudwatchLogsRoleArn(example.arn())
.fieldLogLevel("ERROR")
.build())
.build());
}
}
resources:
example:
type: aws:iam:Role
properties:
name: example
assumeRolePolicy: ${assumeRole.json}
exampleRolePolicyAttachment:
type: aws:iam:RolePolicyAttachment
name: example
properties:
policyArn: arn:aws:iam::aws:policy/service-role/AWSAppSyncPushToCloudWatchLogs
role: ${example.name}
exampleGraphQLApi:
type: aws:appsync:GraphQLApi
name: example
properties:
logConfig:
cloudwatchLogsRoleArn: ${example.arn}
fieldLogLevel: ERROR
variables:
assumeRole:
fn::invoke:
function: aws:iam:getPolicyDocument
arguments:
statements:
- effect: Allow
principals:
- type: Service
identifiers:
- appsync.amazonaws.com
actions:
- sts:AssumeRole
The logConfig block enables CloudWatch Logs integration. The cloudwatchLogsRoleArn grants AppSync permission to write logs. The fieldLogLevel controls verbosity; ERROR captures only failures, while ALL includes all field resolutions. This example creates the IAM role and attaches the AWS-managed policy for CloudWatch Logs access.
Limit query complexity and introspection
APIs exposed to untrusted clients need protection against expensive queries that could consume excessive resources or expose schema details.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
const example = new aws.appsync.GraphQLApi("example", {
authenticationType: "AWS_IAM",
name: "example",
introspectionConfig: "ENABLED",
queryDepthLimit: 2,
resolverCountLimit: 2,
});
import pulumi
import pulumi_aws as aws
example = aws.appsync.GraphQLApi("example",
authentication_type="AWS_IAM",
name="example",
introspection_config="ENABLED",
query_depth_limit=2,
resolver_count_limit=2)
package main
import (
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/appsync"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_, err := appsync.NewGraphQLApi(ctx, "example", &appsync.GraphQLApiArgs{
AuthenticationType: pulumi.String("AWS_IAM"),
Name: pulumi.String("example"),
IntrospectionConfig: pulumi.String("ENABLED"),
QueryDepthLimit: pulumi.Int(2),
ResolverCountLimit: pulumi.Int(2),
})
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;
return await Deployment.RunAsync(() =>
{
var example = new Aws.AppSync.GraphQLApi("example", new()
{
AuthenticationType = "AWS_IAM",
Name = "example",
IntrospectionConfig = "ENABLED",
QueryDepthLimit = 2,
ResolverCountLimit = 2,
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.appsync.GraphQLApi;
import com.pulumi.aws.appsync.GraphQLApiArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
public class App {
public static void main(String[] args) {
Pulumi.run(App::stack);
}
public static void stack(Context ctx) {
var example = new GraphQLApi("example", GraphQLApiArgs.builder()
.authenticationType("AWS_IAM")
.name("example")
.introspectionConfig("ENABLED")
.queryDepthLimit(2)
.resolverCountLimit(2)
.build());
}
}
resources:
example:
type: aws:appsync:GraphQLApi
properties:
authenticationType: AWS_IAM
name: example
introspectionConfig: ENABLED
queryDepthLimit: 2
resolverCountLimit: 2
The queryDepthLimit property restricts how many nested levels a query can traverse (1-75, default unlimited). The resolverCountLimit caps how many resolvers execute per request (1-10000, default 10000). The introspectionConfig property controls whether clients can query the schema structure; DISABLED prevents schema discovery attacks.
Beyond these examples
These snippets focus on specific API-level features: authentication methods (API keys, IAM, Cognito, OIDC, Lambda), schema definition and logging, and query complexity controls. They’re intentionally minimal rather than full GraphQL applications.
The examples may reference pre-existing infrastructure such as Cognito User Pools for user authentication, Lambda functions for custom authorization, and IAM roles for CloudWatch Logs access. They focus on configuring the API rather than provisioning data sources and resolvers.
To keep things focused, common API patterns are omitted, including:
- Data sources and resolvers (configured via companion resources)
- X-Ray distributed tracing (xrayEnabled)
- Enhanced metrics configuration (enhancedMetricsConfig)
- WAF integration for request filtering
- Merged API configuration (apiType: MERGED)
These omissions are intentional: the goal is to illustrate how each API feature is wired, not provide drop-in GraphQL modules. See the AppSync GraphQL API resource reference for all available configuration options.
Let's create AWS AppSync GraphQL APIs
Get started with Pulumi Cloud, then follow our quick setup guide to deploy this infrastructure.
Try Pulumi Cloud for FREEFrequently Asked Questions
Immutability & Lifecycle
apiType and visibility are immutable and cannot be changed once the API is created. Modifying these requires replacing the resource.schema property. You’ll need to manually track schema changes or use external tooling.Authentication & Authorization
API_KEY, AWS_IAM, AMAZON_COGNITO_USER_POOLS, OPENID_CONNECT, and AWS_LAMBDA.additionalAuthenticationProviders to add secondary authentication methods beyond the primary authenticationType.aws.lambda.Permission resource granting AppSync invoke access. Set principal to appsync.amazonaws.com and sourceArn to the API’s ARN.API Configuration & Limits
introspectionConfig defaults to ENABLED. Set it to DISABLED to prevent introspection, which will produce errors if clients attempt to use it.queryDepthLimit defaults to 0 (no limit). You can set it between 1 and 75 nested levels. Queries exceeding the limit will produce errors.resolverCountLimit defaults to 0, which sets the limit to 10000. You can specify a value between 1 and 10000. Requests exceeding the limit will produce errors.apiType is set to MERGED, you must also provide mergedApiExecutionRoleArn with the ARN of the execution role.Logging & Monitoring
logConfig with cloudwatchLogsRoleArn and fieldLogLevel. The IAM role must have the AWSAppSyncPushToCloudWatchLogs managed policy attached.xrayEnabled defaults to false. Set it to true to enable X-ray tracing.Using a different cloud?
Explore integration guides for other cloud providers: