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 may reference Cognito User Pools, Lambda authorizers, or IAM roles that must exist separately. The examples are intentionally small. Combine them with your own resolvers, data sources, and client applications.
Authenticate with API keys for public access
Many GraphQL APIs start with API key authentication for simple, public-facing endpoints where you want to 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. This works well for public APIs where you control access through key distribution and rotation rather than individual user accounts.
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 credentials. This integrates naturally with Lambda functions, EC2 instances, and other AWS services that already have IAM roles. No additional credential management is needed.
Authenticate users through Cognito User Pools
Consumer-facing applications typically authenticate end users through Cognito User Pools, which handle sign-up, sign-in, and token management.
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 determines what happens when a user’s token is valid but they lack explicit permissions (ALLOW or DENY). The userPoolId points to your existing Cognito User Pool.
Implement custom authorization with Lambda
Teams with complex authorization logic often use Lambda authorizers to evaluate custom rules, check external systems, or enforce business-specific access policies.
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}
The lambdaAuthorizerConfig property points to a Lambda function that receives request context and returns an authorization decision. The lambda.Permission resource grants AppSync permission to invoke your authorizer function. This enables authorization logic that goes beyond what IAM policies or Cognito groups can express.
Support multiple authentication methods simultaneously
APIs serving different client types often need multiple authentication methods, such as API keys for public access 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 define secondary authentication methods beyond the primary authenticationType. Clients can choose which method to use based on their context. This example combines API_KEY for public clients with AWS_IAM for internal services.
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 language format. This defines your API’s type system: what queries clients can make, what data they receive, and how types relate. AppSync uses this schema to validate requests and route them to resolvers.
Send API logs to CloudWatch
Production APIs need observability into request patterns, errors, and performance. AppSync can send logs to CloudWatch for monitoring and debugging.
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 logging. The cloudwatchLogsRoleArn points to an IAM role that grants AppSync permission to write logs. The fieldLogLevel controls verbosity: ERROR logs only failures, while ALL logs every field resolution. The example creates the necessary IAM role with the AWS-managed policy for CloudWatch Logs.
Limit query complexity and control 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, or 0 for unlimited). The resolverCountLimit caps how many resolvers execute per request (1-10000, or 0 for the default 10000). The introspectionConfig property controls whether clients can query the schema itself (ENABLED or DISABLED). These limits prevent resource exhaustion from malicious or poorly-written queries.
Beyond these examples
These snippets focus on specific GraphQL API features: authentication methods (API keys, IAM, Cognito, Lambda, OIDC), schema definition and logging, and query complexity controls. They’re intentionally minimal rather than full API deployments.
The examples may reference pre-existing infrastructure such as Cognito User Pools for user authentication, Lambda functions for custom authorization, and IAM roles and policies for logging. They focus on configuring the API rather than provisioning everything around it.
To keep things focused, common API patterns are omitted, including:
- WAF integration for request filtering (shown but not explained)
- X-ray tracing (xrayEnabled)
- Enhanced metrics configuration
- Merged API configuration (apiType: MERGED)
- Visibility controls (GLOBAL vs PRIVATE)
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
Authentication & Authorization
API_KEY, AWS_IAM, AMAZON_COGNITO_USER_POOLS, OPENID_CONNECT, and AWS_LAMBDA.authenticationType to AWS_LAMBDA and configure lambdaAuthorizerConfig with your Lambda ARN. You must also create an aws.lambda.Permission resource with principal set to appsync.amazonaws.com and sourceArn pointing to your API’s ARN.authenticationType and add additional methods using additionalAuthenticationProviders.API Configuration & Immutability
apiType and visibility properties are immutable and cannot be changed after the API is created. Modifying these requires recreating the API.GRAPHQL is a standard AppSync API, while MERGED combines multiple source APIs. The MERGED type requires mergedApiExecutionRoleArn to be set.introspectionConfig is ENABLED, visibility is GLOBAL (public), and xrayEnabled is false.queryDepthLimit defaults to 0 (no limit) with a range of 1-75 nested levels. resolverCountLimit defaults to 0 (which sets it to 10000) with a range of 1-10000. Both produce errors if operations exceed the configured limits.Schema Management
schema property. You’ll need to manually verify if the schema changes outside of Pulumi.schema property with GraphQL schema language format as shown in the examples.Logging & Monitoring
logConfig with cloudwatchLogsRoleArn pointing to an IAM role that has the AWSAppSyncPushToCloudWatchLogs managed policy attached.aws.wafv2.WebAclAssociation resource with resourceArn set to your API’s ARN and webAclArn pointing to your Web ACL.Using a different cloud?
Explore integration guides for other cloud providers: