Skip to content

AWS Amplify Gen 2 Schema difference between Mutation and Query

0

I'm following the tutorial and instructions presented in the AWS Amplify Gen 2 Backend Auth tutorial here, when I ran into issues running the code. The code refused to build due to this error:

19 h 46 min 58 s [ERROR] [SchemaError] 1 problem(s) have been found with your schema
Resolution: See the underlying error message for details about what the problems are and resolve them before attempting this action again
19 h 46 min 58 s Stack Trace for SchemaError
19 h 46 min 58 s SchemaError: 1 problem(s) have been found with your schema

The following Stack Trace doesn't have any relevant information. After trial-and-error: I located the issue to be this piece of code:

import type { ClientSchema } from "@aws-amplify/backend"
import { a, defineData } from "@aws-amplify/backend"
import { addUserToGroup } from "./resource"

const schema = a.schema({
  addUserToGroup: a
    .mutation()
    .arguments({
      userId: a.string().required(),
      groupName: a.string().required(),
    })
    .authorization((allow) => [allow.group("ADMINS")])
    .handler(a.handler.function(addUserToGroup))
    .returns(a.json())
})

export type Schema = ClientSchema<typeof schema>

export const data = defineData({
  schema,
  authorizationModes: {
    defaultAuthorizationMode: "iam",
  },
})

I managed to fix it and have it build and run with no issues by changing the .mutation() to .query(), as shown below. Can someone explain why this works? And what I should keep in mind when building schemas for mutations and queries?

import type { ClientSchema } from "@aws-amplify/backend"
import { a, defineData } from "@aws-amplify/backend"
import { addUserToGroup } from "./resource"

const schema = a.schema({
  addUserToGroup: a
    .query()
    .arguments({
      userId: a.string().required(),
      groupName: a.string().required(),
    })
    .authorization((allow) => [allow.group("ADMINS")])
    .handler(a.handler.function(addUserToGroup))
    .returns(a.json())
})

export type Schema = ClientSchema<typeof schema>

export const data = defineData({
  schema,
  authorizationModes: {
    defaultAuthorizationMode: "iam",
  },
})
1 Answer
-1

In AWS Amplify Gen 2, the distinction between queries and mutations is based on their purpose and effect on backend data:

  • Queries are used when you only need to read data and will not modify any backend data.
  • Mutations are used when your operation will modify backend data.

In your specific case, the function addUserToGroup suggests that you're modifying data by adding a user to a group. Based on this naming convention, it would typically be more appropriate to use a mutation rather than a query.

However, the fact that changing from .mutation() to .query() fixed your issue suggests there might be something in the implementation of the addUserToGroup function that aligns better with query behavior. Without seeing the implementation details of that function, it's difficult to pinpoint exactly why the query worked while the mutation failed.

When building schemas for mutations and queries in Amplify Gen 2, keep these considerations in mind:

  1. Use queries for read-only operations
  2. Use mutations for operations that create, update, or delete data
  3. Both queries and mutations require a return type and can optionally have arguments
  4. Both can be configured with custom business logic handlers

If your operation is truly modifying data by adding a user to a group, you might want to investigate why the mutation isn't working rather than using a query as a workaround, as this could lead to confusion for other developers working with your code.
Sources
Add custom queries and mutations - AWS Amplify Gen 2 Documentation
Add custom queries and mutations - AWS Amplify Gen 2 Documentation
Add custom queries and mutations - AWS Amplify Gen 2 Documentation
Add custom queries and mutations - AWS Amplify Gen 2 Documentation

answered 14 days ago
  • This is not useful, as I am simply following the tutorial from AWS Amplify documents, the handler implementation is exactly the same:

    import type { Schema } from "../resource"
    import { env } from "$amplify/env/add-user-to-group"
    import {
      AdminAddUserToGroupCommand,
      CognitoIdentityProviderClient,
    } from "@aws-sdk/client-cognito-identity-provider"
    
    type Handler = Schema["addUserToGroup"]["functionHandler"]
    const client = new CognitoIdentityProviderClient()
    
    export const handler: Handler = async (event) => {
      const { userId, groupName } = event.arguments
      const command = new AdminAddUserToGroupCommand({
        Username: userId,
        GroupName: groupName,
        UserPoolId: env.AMPLIFY_AUTH_USERPOOL_ID,
      })
      const response = await client.send(command)
      return response
    }