Examples

You are currently viewing the legacy GraphQL Transformer documentation. View latest documentation

Simple Todo

1type Todo @model {
2 id: ID!
3 name: String!
4 description: String
5}

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: String
15 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 id
6 name
7 }
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 id
15 title
16 blog {
17 id
18 name
19 }
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 id
27 content
28 post {
29 id
30 title
31 blog {
32 id
33 name
34 }
35 }
36 }
37}
38
39# Get a blog, its posts, and its posts comments.
40query GetBlog($blogId: ID!) {
41 getBlog(id: $blogId) {
42 id
43 name
44 posts(filter: { title: { eq: "My Post!" } }) {
45 items {
46 id
47 title
48 comments {
49 items {
50 id
51 content
52 }
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 id
65 name
66 posts {
67 # or try adding: posts(filter: { title: { eq: "My Post!" } })
68 items {
69 id
70 title
71 comments {
72 # and so on ...
73 items {
74 id
75 content
76 }
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 Task
2 @model
3 @auth(
4 rules: [
5 {
6 allow: groups
7 groups: ["Managers"]
8 mutations: [create, update, delete]
9 queries: null
10 }
11 {
12 allow: groups
13 groups: ["Employees"]
14 mutations: null
15 queries: [get, list]
16 }
17 ]
18 ) {
19 id: ID!
20 title: String!
21 description: String
22 status: String
23}
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 id
11 title
12 description
13 }
14}
15
16# Get a task. Allowed if an employee.
17query GetTask($taskId: ID!) {
18 getTask(id: $taskId) {
19 id
20 title
21 description
22 }
23}
24
25# Automatically inject the username as owner attribute.
26mutation CreatePrivateNote {
27 createPrivateNote(input: { content: "A private note of user 1" }) {
28 id
29 content
30 }
31}
32
33# Unauthorized error if not owner.
34query GetPrivateNote($privateNoteId: ID!) {
35 getPrivateNote(id: $privateNoteId) {
36 id
37 content
38 }
39}
40
41# Return only my own private notes.
42query ListPrivateNote {
43 listPrivateNote {
44 items {
45 id
46 content
47 }
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 id
4 content
5 version
6 }
7}
8
9mutation Update($noteId: ID!) {
10 updateNote(
11 input: { id: $noteId, content: "A second version", expectedVersion: 1 }
12 ) {
13 id
14 content
15 version
16 }
17}
18
19mutation Delete($noteId: ID!) {
20 deleteNote(input: { id: $noteId, expectedVersion: 2 }) {
21 id
22 content
23 version
24 }
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: String
5 comments: [Comment] @connection(name: "TodoComments")
6}
7type Comment @model {
8 id: ID!
9 content: String
10 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.

  1. 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: String
4 todo: Todo @connection(name: "TodoComments")
5}
  1. 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.

  2. 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): Comment
3 @aws_subscribe(mutations: ["createComment"])
4 onUpdateComment(id: ID, content: String): Comment
5 @aws_subscribe(mutations: ["updateComment"])
6 onDeleteComment(id: ID, content: String): Comment
7 @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.

  1. 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: String
4 todo: Todo @connection(name: "TodoComments")
5 commentTodoId: String # This references the commentTodoId field in DynamoDB
6}
  1. 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.

  2. 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): Comment
3 @aws_subscribe(mutations: ["createComment"])
4 onUpdateComment(id: ID, commentTodoId: String): Comment
5 @aws_subscribe(mutations: ["updateComment"])
6 onDeleteComment(id: ID, commentTodoId: String): Comment
7 @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.