amplify-js
amplify-js copied to clipboard
Can't send AWSJSON array values using aws-amplify and graphql
Before opening, please confirm:
- [X] I have searched for duplicate or closed issues and discussions.
- [X] I have read the guide for submitting bug reports.
- [X] I have done my best to include a minimal, self-contained set of instructions for consistently reproducing the issue.
JavaScript Framework
Vue
Amplify APIs
GraphQL API
Amplify Version
v6
Amplify Categories
api
Backend
Amplify CLI
Environment information
# Put output below this line
System:
OS: macOS 14.4.1
CPU: (10) arm64 Apple M1 Pro
Memory: 63.16 MB / 16.00 GB
Shell: 5.9 - /bin/zsh
Binaries:
Node: 18.19.0 - ~/.nvm/versions/node/v18.19.0/bin/node
npm: 10.3.0 - ~/.nvm/versions/node/v18.19.0/bin/npm
pnpm: 9.0.6 - ~/.nvm/versions/node/v18.19.0/bin/pnpm
Browsers:
Safari: 17.4.1
npmPackages:
@aws-sdk/client-dynamodb: ^3.556.0 => 3.556.0
@aws-sdk/lib-dynamodb: ^3.556.0 => 3.556.0
@mdi/font: ^7.4.47 => 7.4.47
@nuxt/eslint: ^0.3.9 => 0.3.9
@nuxtjs/i18n: ^8.3.0 => 8.3.1
@vee-validate/nuxt: ^4.12.6 => 4.12.6
@vee-validate/yup: ^4.12.6 => 4.12.6
aws-amplify: ^6.0.30 => 6.0.30
date-fns: ^3.6.0 => 3.6.0
nuxt: ^3.11.2 => 3.11.2
vite-plugin-vuetify: ^2.0.3 => 2.0.3
vue: ^3.4.21 => 3.4.25
vue-router: ^4.3.0 => 4.3.2
vuetify: ^3.5.16 => 3.5.17
yup: ^1.4.0 => 1.4.0
npmGlobalPackages:
corepack: 0.22.0
gpt-context-feeder: 0.0.1
npm: 10.3.0
pnpm: 9.0.6
tunnelmole: 2.2.14
Describe the bug
I'm developing an application using Nuxt 3 and Amplify.
- I created a data model using Ampify Studio:
enum EventType { ECONOMY BUSINESS POLITICS SPORTS TECHNOLOGY ENTERTAINMENT OTHER } type Event @model @auth(rules: [{allow: public}]) { id: ID! type: EventType! title: String! description: String! date: AWSDate! relatedLinks: [AWSJSON] involvedPeople: [AWSJSON] involvedOrgs: [AWSJSON] } - I configured Amplify in my application:
.graphqlconfig.yml
plugins/aws-amplify.tsprojects: campobomonline: schemaPath: amplify/backend/api/campobomonline/build/schema.graphql includes: - lib/graphql/**/*.ts excludes: - ./amplify/** - lib/API.ts extensions: amplify: codeGenTarget: typescript generatedFileName: lib/API.ts docsFilePath: lib/graphql region: us-west-1 apiId: null maxDepth: 2import { Amplify } from 'aws-amplify' import awsExports from '~/lib/aws-exports' Amplify.configure(awsExports) - When sending empty JSONs, it works. But when I have any items I get
{ data: null, errors: [ { path: null, locations: [Array], message: "Variable 'involvedPeople' has an invalid value." } ] }dao.tsimport { generateClient } from 'aws-amplify/api' import { createEvent, updateEvent, deleteEvent } from '~/lib/graphql/mutations' import { getEvent, listEvents } from '~/lib/graphql/queries' import type { EventPage } from '~/lib/events/model' import { type Event, type CreateEventInput, type UpdateEventInput, type DeleteEventInput, EventType } from '~/lib/API' class EventsDAO { private client constructor() { this.client = generateClient() } ... async createEvent(createInput: CreateEventInput): Promise<Event> { return await this.client.graphql({ query: createEvent, variables: { input: { type: EventType.ECONOMY, title: 'Lorem ipsum dolor sit amet', description: 'Lorem ipsum dolor sit amet', date: '1970-01-01Z', // WORKS! relatedLinks: [], // DOESNT WORK! involvedPeople: ['foo'], involvedOrgs: [], }, }, }).then(({ data }) => data.createEvent) } ... }
Expected behavior
I should be able to send a JSON with items to the backend through the graphql API.
Reproduction steps
- Create a nuxt project https://nuxt.com/docs/getting-started/installation
- Configure Amplify https://nuxt.com/deploy/aws-amplify
- Create a schema having some JSON property using Amplify Studio and pull it from the cloud using amplify-cli. Follow Amplify instructions to configure it.
- Try to send a JSON with items using the graphql library.
Code Snippet
// Put your code below this line.
import { generateClient } from 'aws-amplify/api'
import { createEvent, updateEvent, deleteEvent } from '~/lib/graphql/mutations'
import { getEvent, listEvents } from '~/lib/graphql/queries'
import type { EventPage } from '~/lib/events/model'
import type { EventType, Event, CreateEventInput, UpdateEventInput, DeleteEventInput } from '~/lib/API'
class EventsDAO {
private client
constructor() {
this.client = generateClient()
}
async createEvent(createInput: CreateEventInput): Promise<Event> {
return this.client.graphql({
query: createEvent,
variables: {
input: createInput,
},
}).then(({ data }) => data.createEvent)
}
async getEventById(id: string): Promise<Event> {
return this.client.graphql({
query: getEvent,
variables: {
id,
},
}).then(({ data }) => {
if (!data.getEvent) {
throw createError({ status: 404, message: 'Event not found' })
}
return data.getEvent
})
}
async updateEvent(updateInput: UpdateEventInput): Promise<Event> {
await this.getEventById(updateInput.id) // Check if event exists
// TODO: Implement optimistic locking
return this.client.graphql({
query: updateEvent,
variables: {
input: updateInput,
},
}).then(({ data }) => data.updateEvent)
}
async deleteEvent(deleteInput: DeleteEventInput): Promise<void> {
await this.client.graphql({
query: deleteEvent,
variables: {
input: deleteInput,
},
}).then(({ data }) => {
if (!data.deleteEvent) {
throw createError({ status: 404, message: 'Event not found' })
}
})
}
async queryEventsByType(type: EventType, nextToken?: string | null): Promise<EventPage> {
const results = await this.client.graphql({
query: listEvents,
variables: {
filter: {
type: {
eq: type,
},
},
nextToken,
},
})
return {
items: results.data.listEvents.items,
nextToken: results.data.listEvents.nextToken,
}
}
}
export default EventsDAO
Log output
// Put your logs below this line
ERROR { data: null,
errors:
[ { path: null,
locations: [Array],
message: "Variable 'involvedOrgs' has an invalid value." } ] }
aws-exports.js
const awsmobile = {
"aws_project_region": "us-west-1",
"aws_appsync_graphqlEndpoint": "https://f6koholxxzc5pcqfwmtdjkdlsa.appsync-api.us-west-1.amazonaws.com/graphql",
"aws_appsync_region": "us-west-1",
"aws_appsync_authenticationType": "API_KEY",
"aws_appsync_apiKey": "MY_SECRET_API_KEY"
};
Manual configuration
No response
Additional configuration
No response
Mobile Device
No response
Mobile Operating System
No response
Mobile Browser
No response
Mobile Browser Version
No response
Additional information and screenshots
No response
I could make it work by stringifying the JSON:
eg.:
async createEvent(createInput: CreateEventInput): Promise<Event> {
return this.client.graphql({
query: createEvent,
variables: {
input: {
...createInput,
involvedPeople: JSON.stringify(createInput.involvedPeople),
},
},
}).then(({ data }) => data.createEvent)
}
Given that the GraphQL schema specifies an array, it's logical to anticipate that the generated input would require an array and not a string. Ignoring the type error in the code might be a temporary workaround, but inherently, it doesn't seem appropriate.
Hi @rodrigogs this seems to be expected behavior. At this point, serialization of the data is up to the client. If you would like for the library to handle serialization, I would recommend opening a feature request.
Hi @chrisbonifacio, I appreciate your response, but I must respectfully disagree with the notion that this is expected behavior. The inconsistency arises because the library's generated GraphQL types specify an array for AWSJSON fields, yet the underlying system only accepts a stringified JSON, which leads to confusion and the need for additional client-side handling that one could argue should be intrinsic to the library's functionality.
If the intent is indeed for clients to handle serialization, it would be beneficial for this to be explicitly documented, or better yet, for the type generation to align more closely with the actual data expectations—either by correcting the type definitions or by handling serialization/deserialization within the library itself. This would enhance developer experience and reduce potential errors. Would you consider revisiting this issue in light of this perspective?