Skip to content

Mutations

Read Progress Tracker Example for concepts and design.

name: {TOPOLOGY_NAME}
mutations:
authorizer: authorizer-fn
inputs:
{NAME}: {TYPE_MAPPING}
types:
{NAME}: {TYPE_MAPPING}
resolvers:
{NAME}:
function: {FUNCTION_NAME}
input: {INPUT_OR_TYPE}
output: {TYPE}
subscribe: bool

It is straightforward to define the types as a simple key-value map. For example:

name: mutations-basic
mutations:
authorizer: authorizer-fn
types:
Input:
id: String!
Status:
id: String!
message: String
resolvers:
updateStatus:
function: updater
input: Input
output: Status
subscribe: true

Note that we did not annotate any directives as tc infers the directives based on the resolver definition. This keeps the type definitions clean and succinct.

Inputs are special kind of Types that can be referenced in other Types or Inputs. For example, in the following example, we see that Message input is referenced by ChannelInput.

mutations:
inputs:
Message:
id: String!
text: String!
ChannelInput:
messages: '[Message!]!'
resolvers:
getMessage:
function: foo
input: ChannelInput
output: AWSJSON
subscribe: false

Refer AWS Post

tc provides a set of convenient implicit Types. These Types capture the shape or path access in input entity’s payload.

Input PathInput EntityTarget Type
Event$.detailEventString
EventData$.detail.dataEventString
EventDataJSON*$.detail.dataEventAWSJSON
EventMetadata$.detail.metadataEventString

mutations can be rendered on any Graphql server that provides subscriptions and resolvers. AWS Appsync is the default provider.

tc generates graphql for the given mutation spec and provider.

{
"default": {
"api_name": "mutations-basic_{{sandbox}}",
"authorizer": "authorizer-fn",
"resolvers": {
"updateStatus": {
"entity": "Function",
"input": "Input",
"name": "updateStatus",
"output": "Status",
"target_arn": "arn:aws:lambda:{{region}}:{{account}}:function:{{namespace}}_updater_{{sandbox}}"
}
},
"role_arn": "arn:aws:iam::{{account}}:role/tc-base-appsync-role",
"types": {
"Event": "type Event @aws_lambda @aws_iam { detail: String createdAt: AWSDateTime updatedAt: AWSDateTime }",
"Input": "type Input @aws_lambda @aws_iam { id: String! createdAt: AWSDateTime updatedAt: AWSDateTime}",
"Mutation": "type Mutation { updateStatus(id: String! ): Status@aws_lambda @aws_iam }",
"Query": "type Query { getInput(id: String!): InputgetEvent(id: String!): EventgetStatus(id: String!): Status }",
"Status": "type Status @aws_lambda @aws_iam { id: String! message: String createdAt: AWSDateTime updatedAt: AWSDateTime}",
"Subscription": "type Subscription { subscribeUpdateStatus(id: String!): Status @aws_subscribe(mutations: [\"updateStatus\"]) @aws_lambda @aws_iam\n }"
},
"types_map": {
"Event": {
"detail": "String"
},
"Input": {
"id": "String!"
},
"Status": {
"id": "String!",
"message": "String"
}
}
}
}

To validate the generated graphql, do:

tc validate -c mutations

You should see any errors that are statically determined.

Components in mutation entity:

Terminal window
tc update -s sandbox -e env -c mutations/authorizer
tc update -s sandbox -e env -c mutations/types
tc update -s sandbox -e env -c mutations/roles
tc update -s sandbox -e env -c mutations/RESOLVER_NAME

To place the mutations in separate files that are domain-specific, we can do the following:

name: example
infra: ./infra
mutations:
!mutations ./entities/m1.yml
!mutations ./entities/m2.yml

Where m1 and m2 are self-contained MutationSpecs.

m1.yml
authorizer: my-auth-fn
inputs:
Foo:
text: String!
types:
Message:
id: String!
text: String!
resolvers:
getMessage:
function: foo
input: Message
output: AWSJSON
subscribe: true
m2.yml
authorizer: auth-fn
types:
Data:
id: String!
text: String!
resolvers:
getData:
function: foo
input: Data
output: AWSJSON
subscribe: false