I am not familiar with appsync's syntax with graphql. I am trying to update one of my entities using app sync. I used Amazon's option to automatically allocate resources and connect them to DynamoDB. Here is my entity:
type Property {
id: ID!
address: String!
listedDate: AWSDate!
notes: String
homeType: String!
tenantName: String!
ownerName: String!
leaseExpDate: AWSDate!
}
Inside of my mutations, I have this:
type Mutation {
updateProperty(input: UpdatePropertyInput!): Property
}
Along with this input:
input UpdatePropertyInput {
id: ID!
address: String
listedDate: AWSDate
notes: String
homeType: String
tenantName: String
ownerName: String
leaseExpDate: AWSDate
}
Here is my attempt at the mutation to update the given property:
mutation updateProperty {
updateProperty(input: UpdatePropertyInput(id: 'myID')) {
address: String!
}
}
The closest implementation that I found in the appsync's docs can be found here.
Input objects are constructed using brackets like below:
mutation updateProperty {
updateProperty(input: {
id: "myID",
address: "myAddress"
}) {
address
}
}
Here is some additional documentation on input objects can be found here:
https://graphql.org/learn/schema/#input-types
https://graphql.org/graphql-js/mutations-and-input-types/
Related
I'm fairly new to Amplify. I ran the amplify commands to create the src/models/index.d.ts and the generated API file, src/app/API.ts files. Each of these have the same types generated except that embedded collections generated via #belogsTo and #hasMany is not on the type in API.ts but IS on index.d.ts. When I try running the code I have a JSON object that I've cast to the model in src/app/API.ts. Like I say, there is an embedded collection that does NOT show up on the API file. Here is what I have for the schema file schema.graphql.
EDIT: It appears there are multiple ways to do the same thing, such as getting, updating, and deleting data. I think that using API.ts is the latests way to do it? I'm just totally confused by all of this.
type Blog #model {
id: ID! #primaryKey
name: String!
posts: [Post] #hasMany
}
type Post #model {
id: ID! #primaryKey
title: String!
blog: Blog #belongsTo
comments: [Comment] #hasMany
}
type Comment #model {
id: ID! #primaryKey
post: Post #belongsTo
content: String!
}
The API model that was generated does not have comments on type Post. Here is the generated code in the API file:
export type CreatePostInput = {
id?: string | null;
title: string;
blogPostsId?: string | null;
};
That is the type that is passed into CreatePostInput. When I try to specify the json:
const json = {
blogPostsId: 'Some Random UUID String',
title: 'MyPost',
} as Post;
I cannot add a comments array to this json because CreatePostInput and Post models does not contain comments that I specified on the schema.graphql.
My question is, first, what definition of Blog should I be using, the one in the index.t.ds file or the definition in the API file? If the answer is the one in index.d.ts, how to do go about creating one because the CreateBlogInput is the type that CreatePost in API.ts file.
I've tried different things that I've found on the interwebs from AWS blogs to Medium posts.
I am currently developing an eCommerce App in React Native Expo that utilizes AWS amplify and I am trying to connect the API and database to it.
After running 'amplify push', I get the following error message:
� An error occurred during the push operation: Unknown directive 'connection'. Either remove the directive from the schema or add a transformer to handle it.
For some reason, it doesn't recognize #connection as its own directive.
The block of code in the schema.graphql that utilizes this directive is the following:
type CartProduct #model #auth(rules: [{allow: public}]){
id: ID!
userSub: String!
quantity: Int!
option: String
productID: ID!
product: Product #connection(fields: ["productID"])
}
I haven't found a solution anywhere and I appreciate anyone who can help me with this.
This github issue in the aws-amplify repo helped me solve a similar error. The gist of the problem is the graphql transformer version that interprets the schema definition was upgraded to v2 and the #key and #connection directives are in a version 1 directives.
For version 2 I used #hasMany and #hasOne directives.
type PurchaseOrder #model #auth(rules: [{ allow: owner }]) {
id: ID!
poNumber: String
dateOrdered: AWSDateTime
dateRequested: AWSDateTime
dateReceived: AWSDateTime
notes: String
subtotal: Float
taxRate: Float
salesTax: Float
priceAdjustment: Float
discount: Float
total: Float
requestor: String
paymentTerms: String
shipping: Float
comments: String
billingAddress: Address #hasOne
shippingAddress: Address #hasOne
shippingInformation: String
customerId: String
createdAt: AWSDateTime!
updatedAt: AWSDateTime!
poItems: [PoItem] #hasMany
attachments: [Attachment] #hasMany
vendorID: ID!
vendor: Vendor #hasOne
}
I am trying to compose a federated apollo service with a gateway and 3 implementing microservices.
MS1:
type Movie #key(fields: "id name") {
id: String!
name: String
}
MS2:
type Location #key(fields: "id") {
id: String!
longitude: Float!
latitude: Float!
}
type Movie #key(fields: "id") #extends {
id: String! #external
location: Location
}
MS3:
type Award #key(fields: "name"){
name: String!
count: Int
}
type Movie #key(fields: "name") #extends {
name: String! #external
award: Award
}
MS1 provides a name and an id.
name shall be send to MS3 for the resolving process and id shall be used by MS2 for the resolving process.
This approach worked with an older version of apollo-gateway / apollo-server, but with the latest versions I receive the following error messages.
{"stack":"Error: A valid schema couldn't be composed. The following composition errors were found:\n\t[ms2] Movie -> extends from ms1 but specifies an invalid #key directive. Valid #key directives are specified by the originating type. Available #key directives for this type are:\n\t#key(fields: \"id name\")\n ...}
An approach to provide the keys like this didn't work either:
type Movie #key(fields: "id") #key(fields: "name") {
What does the schema have to look like to provide the described use case?
I recently added a #key directive to a schema field so that I could search by that field, although I now get an error implying the previously correct data type is not what is expected. It says it expects a string but got a list, although the field is a list containing an enum.
Is it possible to query by a specific field without using #key? If not, how can I create records when the #key (seemingly) changes the expected type of a list to a string?
Below is my code, I added the #key to the categories list, but now when I try to create a new Journey I get the error shown below.
This is the schema:
type Journey #model
#auth(rules: [{ allow: owner, operations: [create, delete, update] }])
#key(name: "getJourneysByCategories", fields: ["categories"], queryField: "getJourneysByCategories")
#key(name: "getJourneysByName", fields: ["name"], queryField: "getJourneysByName") {
id: ID!
name: String!
description: String
coverImage: String
isPrivate: Boolean!
members: [JourneyUsersBridge] #connection(name: "JourneyUsers")
moderators: [JourneyModeratorsBridge] #connection(name: "ModeratedBy")
creator: User! #connection(name: "JourneyCreator")
goals: [Goal] #connection(name: "JourneyGoals")
posts: [Post] #connection(name: "JourneyPosts")
categories: [JourneyCategory!]!
}
This is an example of the code used to create a Journey:
type CreateJourneyInput = {
name: string;
description?: string | null;
coverImage?: string | null;
isPrivate: boolean;
categories: Array<JourneyCategory | null>;
journeyCreatorId: string;
};
const journey: CreateJourneyInput = {
name: 'My GraphQL Journey',
description: 'This Journey was made using GraphQL minus DataStore!',
isPrivate: false,
categories: [JourneyCategory.EXMAMPLE],
journeyCreatorId: userId
};
const result = await API.graphql(
graphqlOperation(mutations.createJourney, { input: journey })
);
This is the full error:
"One or more parameter values were invalid: Type mismatch for Index Key categories Expected: S Actual: L IndexName: getJourneysByCategories (Service: AmazonDynamoDBv2; Status Code: 400; Error Code: ValidationException; Request ID: U4EB7HPO1GU5LHVAOPMGAJJHANVV4KQNSO5AEMVJF66Q9ASUAAJG)"
So I removed the getJourneysByCategories key and the upload worked fine. What's happening here and why?
I just want to be able to query by categories - perhaps #key wasn't the right route to take? Does the key directive not work with lists?
I am new to both graphql & AWS Amplify, so please forgive any ignorance :)
I have a graphql schema like this:
type Location #model #auth(rules: [{allow: owner}]){
street: String
city: String
state: String
zip: String
}
type Trip #model #auth(rules: [{allow: owner}]){
id: String!
...
location: Location
}
I'm trying to create both the location and the trip at the same time with a mutation request like this:
mutation {
createTrip(input: {
id: "someIdentifier",
location: {
street: "somewhere"
}
}) {
id
location {
street
}
}
}
But I'm getting an error like this:
{
"data": null,
"errors": [
{
"path": null,
"locations": [
{
"line": 2,
"column": 21,
"sourceName": null
}
],
"message": "Validation error of type WrongType: argument 'input' with value '...' contains a field not in 'CreateTripInput': 'location' # 'createTrip'"
}
]
}
Checking the generated schema.graphql file, I see that there is indeed no location object on the input model:
input CreateTripInput {
id: String!
...
}
How can I have amplify generate the proper input schema so that I can create both the Trip and the location objects at the same time?
I was able to get an answer from the aws-amplify team here. To summarize:
Both Trip and Location have model directive. There isn't a #connection directive connecting the Trip with Location. The two options to "resolving" this is:
Update the schema connecting the models if you want them to be in 2 separate tables and want the ability to query Trip based on Location. Using 2 separate table you won't be able to create both Trip and Location in a single mutation, though. For example:
type Location #model #auth(rules: [{allow: owner}]){
street: String
city: String
state: String
zip: String
trips: Trip #connection(name:"TripLocation")
}
type Trip #model #auth(rules: [{allow: owner}]){
id: String!
location: Location #connection(name:"TripLocation")
}
The second option, if the Location data is very specific to a trip and you don't want to create a separate table, then get rid of #model directive from your Location type. Doing so would allow you to create Location as a part of same mutation.
type Location {
street: String
city: String
state: String
zip: String
}
type Trip #model #auth(rules: [{allow: owner}]){
id: String!
location: Location
}
The later was the solution that I moved forward with.