Examples
Simple Todo
1type Todo @model {2 id: ID!3 name: String!4 description: String5}
Blog
1type Blog @model {2 id: ID!3 name: String!4 posts: [Post] @connection(name: "BlogPosts")5}6type Post @model {7 id: ID!8 title: String!9 blog: Blog @connection(name: "BlogPosts")10 comments: [Comment] @connection(name: "PostComments")11}12type Comment @model {13 id: ID!14 content: String15 post: Post @connection(name: "PostComments")16}
Blog Queries
1# Create a blog. Remember the returned id.2# Provide the returned id as the "blogId" variable.3mutation CreateBlog {4 createBlog(input: { name: "My New Blog!" }) {5 id6 name7 }8}9
10# Create a post and associate it with the blog via the "postBlogId" input field.11# Provide the returned id as the "postId" variable.12mutation CreatePost($blogId: ID!) {13 createPost(input: { title: "My Post!", postBlogId: $blogId }) {14 id15 title16 blog {17 id18 name19 }20 }21}22
23# Create a comment and associate it with the post via the "commentPostId" input field.24mutation CreateComment($postId: ID!) {25 createComment(input: { content: "A comment!", commentPostId: $postId }) {26 id27 content28 post {29 id30 title31 blog {32 id33 name34 }35 }36 }37}38
39# Get a blog, its posts, and its posts comments.40query GetBlog($blogId: ID!) {41 getBlog(id: $blogId) {42 id43 name44 posts(filter: { title: { eq: "My Post!" } }) {45 items {46 id47 title48 comments {49 items {50 id51 content52 }53 }54 }55 }56 }57}58
59# List all blogs, their posts, and their posts comments.60query ListBlogs {61 listBlogs {62 # Try adding: listBlog(filter: { name: { eq: "My New Blog!" } })63 items {64 id65 name66 posts {67 # or try adding: posts(filter: { title: { eq: "My Post!" } })68 items {69 id70 title71 comments {72 # and so on ...73 items {74 id75 content76 }77 }78 }79 }80 }81 }82}
Task App
Note: To use the @auth directive, the API must be configured to use Amazon Cognito user pools.
1type Task2 @model3 @auth(4 rules: [5 {6 allow: groups7 groups: ["Managers"]8 mutations: [create, update, delete]9 queries: null10 }11 {12 allow: groups13 groups: ["Employees"]14 mutations: null15 queries: [get, list]16 }17 ]18 ) {19 id: ID!20 title: String!21 description: String22 status: String23}24type PrivateNote @model @auth(rules: [{ allow: owner }]) {25 id: ID!26 content: String!27}
Task Queries
1# Create a task. Only allowed if a manager.2mutation CreateTask {3 createTask(4 input: {5 title: "A task"6 description: "A task description"7 status: "pending"8 }9 ) {10 id11 title12 description13 }14}15
16# Get a task. Allowed if an employee.17query GetTask($taskId: ID!) {18 getTask(id: $taskId) {19 id20 title21 description22 }23}24
25# Automatically inject the username as owner attribute.26mutation CreatePrivateNote {27 createPrivateNote(input: { content: "A private note of user 1" }) {28 id29 content30 }31}32
33# Unauthorized error if not owner.34query GetPrivateNote($privateNoteId: ID!) {35 getPrivateNote(id: $privateNoteId) {36 id37 content38 }39}40
41# Return only my own private notes.42query ListPrivateNote {43 listPrivateNote {44 items {45 id46 content47 }48 }49}
Conflict Detection
1type Note @model @versioned {2 id: ID!3 content: String!4 version: Int! # You can leave this out. Validation fails if this is not a int like type (Int/BigInt) and is always coerced to non-null.5}
Conflict Detection Queries
1mutation Create {2 createNote(input: { content: "A note" }) {3 id4 content5 version6 }7}8
9mutation Update($noteId: ID!) {10 updateNote(11 input: { id: $noteId, content: "A second version", expectedVersion: 1 }12 ) {13 id14 content15 version16 }17}18
19mutation Delete($noteId: ID!) {20 deleteNote(input: { id: $noteId, expectedVersion: 2 }) {21 id22 content23 version24 }25}
Common Patterns for the API Category
The Amplify CLI exposes the GraphQL Transform libraries to help create APIs with common patterns and best practices baked in but it also provides number of escape hatches for those situations where you might need a bit more control. Here are a few common use cases you might find useful.
Filter Subscriptions by model fields and/or relations
In multi-tenant scenarios, subscribed clients may not always want to receive every change for a model type. These are useful features for limiting the objects that are returned by a client subscription. It is crucial to remember that subscriptions can only filter by what fields are returned from the mutation query. Keep in mind, these two methods can be used together to create truly robust filtering options.
Consider this simple schema for our examples:
1type Todo @model {2 id: ID!3 name: String!4 description: String5 comments: [Comment] @connection(name: "TodoComments")6}7type Comment @model {8 id: ID!9 content: String10 todo: Todo @connection(name: "TodoComments")11}
Filtering by type fields
This is the simpler method of filtering subscriptions, as it requires one less change to the model than filtering on relations.
- Add the subscriptions argument on the @model directive, telling Amplify to not generate subscriptions for your Comment type.
1type Comment @model(subscriptions: null) {2 id: ID!3 content: String4 todo: Todo @connection(name: "TodoComments")5}
-
Run
amplify push
at this point, as running it after adding the Subscription type will throw an error, claiming you cannot have two Subscription definitions in your schema. -
After the push, you will need to add the Subscription type to your schema, including whichever scalar Comment fields you wish to use for filtering (content in this case):
1type Subscription {2 onCreateComment(content: String): Comment3 @aws_subscribe(mutations: ["createComment"])4 onUpdateComment(id: ID, content: String): Comment5 @aws_subscribe(mutations: ["updateComment"])6 onDeleteComment(id: ID, content: String): Comment7 @aws_subscribe(mutations: ["deleteComment"])8}
Filtering by related (@connection designated) type
This is useful when you need to filter by what Todo objects the Comments are connected to. You will need to augment your schema slightly to enable this.
- Add the subscriptions argument on the @model directive, telling Amplify to not generate subscriptions for your Comment type. Also, just as importantly, you will be utilizing an auto-generated column from DynamoDB by adding
commentTodoId
to our Comment model:
1type Comment @model(subscriptions: null) {2 id: ID!3 content: String4 todo: Todo @connection(name: "TodoComments")5 commentTodoId: String # This references the commentTodoId field in DynamoDB6}
-
You should run
amplify push
at this point, as running it after adding the Subscription type will throw an error, claiming you cannot have two Subscription definitions in your schema. -
After the push, you will need to add the Subscription type to your schema, including the
commentTodoId
as an optional argument:
1type Subscription {2 onCreateComment(commentTodoId: String): Comment3 @aws_subscribe(mutations: ["createComment"])4 onUpdateComment(id: ID, commentTodoId: String): Comment5 @aws_subscribe(mutations: ["updateComment"])6 onDeleteComment(id: ID, commentTodoId: String): Comment7 @aws_subscribe(mutations: ["deleteComment"])8}
The next time you run amplify push
or amplify api gql-compile
, your subscriptions will allow an id
and/or commentTodoId
argument on a Comment subscription. As long as your mutation on the Comment type returns the specified argument field from its query, AppSync filters which subscription events will be pushed to your subscribed client.