Appsync Update and Delete mutation not working - reactjs

I am using AppSync for my APP. Here is a quick look of my Schema.graphql file
type Item #model
#auth(rules: [
{ allow: public, provider: apiKey, operations: [read] },
{ allow: groups, groups: ["admin"] }
]) {
id: ID!
name: String!
soldUnits: String!
soldAs: [Float!]
price: Float!
isAvailable: Boolean!
availableAmount: Float!
category: String!
isVeg: Boolean!
offer: [String!]
about: String
storage: String
benifits: String
otherInfo: String
rating: Int
keywords: [String!]
reviews: [String]
images: [String]
updatedBy: String
addedBy: String
qty: Int
inventroy: Inventory #connection(name: "ItemInventory")
}
type User #model {
id: ID!
firstName: String!
lastName: String!
about: String
phoneNumber: String
email: String
countryCode: String
addresses: [Address] #connection
orders: [Order] #connection(name: "OwnOrder")
}
type CartItem {
id: ID!
count: Int!
name: String!
price: Float
}
type Address #model {
id: ID!
lat: Float!
long: Float!
fullAddress: String!
apartment: String!
street: String
area: String!
district: String!
city: String
state: String!
zip: Int!
country: String!
phoneNumber: String!
}
type InventoryAddress #model {
id: ID!
address: Address #connection
inventroy: Inventory! #connection(name: "InventoryAddress")
}
type Order #model {
id: ID!
orderdate: AWSDate!
ordertime: AWSTime!
deliverySlot: String!
deliveryDate: AWSDate!
deliveryInput: String!
deliveryPhoneNumber: String!
deliveryPhoneCountryCode: String!
deliveryAddress: String!
deliveredTime: AWSDate
deliveredDate: AWSDate
deliveryCharges: Float!
totalAmount: Float!
paidAmount: Float!
discount: Float!
unpaidAmount: Float!
status: String!
paymentMethod: String!
paymentId: String!
itemsCount: Int!
items: [CartItem]
deliverAssignedTo: Patron #connection(name: "PatronOrder")
owner: User #connection(name: "OwnOrder")
inventroyDetails: Inventory #connection(name: "InventoryOrder")
}
type Patron #model {
id: ID!
age: Int!
firstName: String!
lastName: String!
about: String
workTime: String
rating: Int!
reviews: [String]
addressProof: String!
role: String
workArea: Address #connection
address: Address #connection
deliveries: [Order] #connection(name: "PatronOrder")
inventroyDetails: Inventory! #connection(name: "PatronInventory")
addedItems: [Item] #connection
}
type Inventory #model {
id: ID!
address: InventoryAddress #connection(name: "InventoryAddress")
patron: [Patron] #connection(name: "PatronInventory")
items: [Item] #connection(name: "ItemInventory")
orders: [Order] #connection(name: "InventoryOrder")
manager: Patron #connection
admins: [Patron] #connection
}
This is my GraphQL Schema generated in AppSync.
I am able to query the data and do create mutation, but update and delete mutation is not working.
mutation UpdateAddressInput {
updateAddress(input:{
id:"af5cd7e6-8213-48b6-aa8e-9d2d6999742c",
area:"New Delhi"
}){
id,
area
}
}
This is an example query , as you can see the return data below, it's not reflecting in dynamoDB
{
"data": {
"updateAddress": {
"id": "af5cd7e6-8213-48b6-aa8e-9d2d6999742c",
"area": "Electronic City"
}
}
}

Even working with AWS Amplify, I prefer to go to the AppSync console and select the queries, and mutations this way you'll see what's happening and what's needed behind the scenes to do your mutations.
An update mutation sample bellow, extracted from the AppSync console - instead of using codegen from Amplify.
input UpdateRuralAddressInput {
id: ID!
latitude: String
longitude: String
stateCity: String
status: Int
_version: Int
}
Note that field version is required to do the update.
I'm just pointing it out to help others with this issue, that's how I'm working with Amplify + Appsync client in Lambdas
So, before applying any update mutation execute a "get by id" query, plus update the model that comes from the request body accordingly. This way not only the field version will remains Ok, but other aspects as well.
A sample of updating in the Lambda handler function.
Note: You'll need to delete the property __typename
const updateRuralAddressRequest = JSON.parse(event.body);
const client = await appsyncClient.hydrated();
const ruralAddressQuery = await client.query({ query: gql(queryRuralAddress), variables: { id: updateRuralAddressRequest.id } });
const ruralAddressFromDb = ruralAddressQuery.data.getRuralAddress;
const updateRuralAddressInput = { ...ruralAddressFromDb, ...updateRuralAddressRequest };
delete updateRuralAddressInput.__typename;
const data = await client.mutate({ mutation: gql(updateRuralAddressMutation), variables: { updateRuralAddressInput } });
Notice that both my query and my update mutation must contains the version field.
export const queryRuralAddress = `
query GetRuralAddressByID($id: ID!) {
getRuralAddress(id: $id) {
id,
latitude,
longitude,
stateCity,
status,
_version
}
}
`;
export const updateRuralAddressMutation = `
mutation UpdateRuralAddress($updateRuralAddressInput:UpdateRuralAddressInput!) {
updateRuralAddress(input: $updateRuralAddressInput) {
id
latitude
longitude
stateCity
status,
_version
}
}`;

You’ll see an auto generated field “_version” in your dynamoDB Table. See the value of _version for the ID you want to update area field.when you fetch address,you'll get a field "_version".
Try Something like this
mutation UpdateAddressInput {
updateAddress(input:{
id:"af5cd7e6-8213-48b6-aa8e-9d2d6999742c",
area:"New Delhi",
_version:variable name // _version value in dynamoDB table for
// the desired row.
}){
id,
area
}
}

Related

GraphQL query for interface or union type

We are implementing an app in React-Naitive and for this we are using aws and amplify. Now we are trying to get all elements of an interface or union type in graphql. The Interface is calling TrackingItem and the type which are implementing this is called UserFood and UserSymptom. We tried this also, with union and just a array of TrackingItems. But with every possibility we don’t get any element. The return value is just null and we are expect the ID of TrackingItems, or in case of getAllTrackingItems an array of IDs from TrackingItem.
Graphql-schema:
type Query {
getAllTrackingItems: [TrackingItem]
# Retrieve tracking items
findTrackingItem(id: ID!): TrackingItem
# Search across all UnionTrackingItems
search(id: ID!): [UnionTrackingItems]
}
union UnionTrackingItems = UserSymptom | UserFood
interface TrackingItem {
id: ID!
userId: ID!
}
type UserFood implements TrackingItem #model {
id: ID!
userId : ID!
type: String!
foodId: ID!
food : Food #connection(fields: ["foodId"])
}
type UserSymptom implements TrackingItem #model {
id: ID!
userId : ID!
type: String!
symptomId: ID!
symptom : Symptom #connection(fields: ["symptomId"])
strenght: Int
}
Our queries which we are testing after amplify mock:
query MyQuery {
getAllTrackingItems {
id
}
findTrackingItem(id: 1) {
id
}
search(id: 1) {
... on UserFood {
id
}
}
getUserFood(id: 1) {
id
}
}
Our results:
{
"data": {
"getAllTrackingItems": null,
"findTrackingItem": null,
"search": null,
"getUserFood": {
"id": "1"
}
}
}
Can anyone help? Thank you!

AWS Amplify Avoid #connection queries on an #key or index query generating a list

I have a model for orders, I made an index that would let me query the orders based on what month and year they were created.
Now that I am able to query those orders, I want to avoid unnecessary connection (order-vendor) queries every time I query using that month-year index since I only want the list of the orders' number and status. Is there a way that I can do that?
here is my schema:
type Vendor #model #searchable{
id: ID!
vendorName: String!
location: String!
telNo: String!
terms: String!
createdAt: AWSDateTime!
updatedAt: AWSDateTime!
}
type PurchaseOrder #model #searchable
#key(name:"MonthYearCreatedAt" fields:["monthYear", "createdAt"] queryField: "purchaseOrderMonthCreatedAt")
{
id: ID!
purchaseOrderNo: String!
vendor: Vendor! #connection
orders:[String!]
totalPrice: Float!
requestedBy: String!
category: String
addNotes: String
status: Status!
monthYear: String!
createdAt: AWSDateTime!
updatedAt: AWSDateTime!
}
You can do that by adapting your query
query getPurchases {
purchaseOrderMonthCreatedAt(monthYear: ..., createdAt: ...) {
items {
totalPrice
}
}
}
vs
query getPurchases {
purchaseOrderMonthCreatedAt(monthYear: ..., createdAt: ...) {
items {
vendor { vendorName }
totalPrice
}
}
}
Using the second query will navigate the vendor connection.

AppSync List Query Returns Empty Array from JS Client App, but Populated Array from AppSync Console

When running a list query from the AppSync console, I get back an array with 3 items (this is expected, as I have three corresponding items in my DynamoDB table).
When I run the exact same query from my React client application, I get an empty array. I've tried messing around with the #auth decorator in my schema.graphql file, but so far to no avail. I also experience the same behavior when running the query from Postman - I get an empty items array.
Type definition in schema.graphql:
type Item #model #auth(rules: [
{ allow: owner },
{ allow: public, provider: iam, operations: [read] }]) {
id: ID!
itemName: String!
anotherProperty: String!
anotherProperty: String!
anotherProperty: String!
anotherProperty: String
anotherProperty: AnotherType #connection
anotherProperty: String
anotherProperty: String
anotherProperty: String
anotherProperty: String
anotherProperty: String
anotherProperty: SomeType #connection
anotherProperty: [SomeOtherType] #connection(keyName: "byItemID", fields: ["id"])
anotherProperty: String
anotherProperty: [YetAnotherType] #connection(keyName: "byItemID", fields: ["id"])
}
Client code where I call the API (ClojureScript):
(re-frame/reg-event-fx
::list-items
(fn list-items-handler []
(-> (.graphql API (graphqlOperation "query { listItems { items { itemName } } }"))
(.then (fn list-items-res [url]
(js/console.log url))))))
Response to call from client application:
{"data":{"listItems":{"items":[]}}}
Same query from the AppSync Console:
query ListItems {
listItems {
items {
itemName
}
}
}
Response to call from AppSync Console:
{
"data": {
"listItems": {
"items": [
{
"itemName": "Thingy"
},
{
"itemName": "Contraption"
},
{
"itemName": "Apparatus"
}
]
}
}
}
I'm not sure what I'm doing wrong. I suspect it has something to do with the permissions set with #auth, but I can't figure out what that might be. Any help would be appreciated. Thanks in advance!

GraphQL Error : Field is not defined in the input type

I have an error in my application. I use Next.js / ApolloClient / GraphQL and Prisma. The error concerns the GraphQL schema and it's use in Mutation:
Error : Reason: 'end_date' Field 'end_date' is not defined in the
input type ArticleCreateInput
I tried to copy/paste the global schema on each file to have the good corresponding data, but it doesn't work.
My data Model (datamodel.prisma):
type Article {
id: ID! #id
title: String!
description: String!
createdAt: DateTime! #createdAt
updatedAt: DateTime! #updatedAt
image: String
maxUserNumber: Int!
greatImage: String
street: String!
begin_date: DateTime!
end_date: DateTime!
price: Int!
user: User!
}
My schema.graphql:
createArticle(
title: String!
description: String!
image: String
maxUserNumber: Int!
greatImage: String
street: String!
begin_date: DateTime!
end_date: DateTime!
price: Int!
): Article!
In my Genertated file (prisma.graphql):
input ArticleCreateInput {
id: ID
title: String!
description: String!
image: String
maxUserNumber: Int
greatImage: String
street: String
begin_date: DateTime
end_date: DateTime
price: Int!
user: UserCreateOneInput!
}
ClientSide Mutation and State:
const CREATE_ARTICLE_MUTATION = gql`
mutation CREATE_ARTICLE_MUTATION(
$title: String!
$description: String!
$image: String
$maxUserNumber: Int!
$greatImage: String
$street: String!
$begin_date: DateTime!
$end_date: DateTime!
$price: Int!
) {
createArticle(
title: $title
description: $description
image: $image
maxUserNumber: $maxUserNumber
greatImage: $greatImage
street: $street
begin_date: $begin_date
end_date: $end_date
price: $price
) {
id
}
}
`;
export class CreateArticle extends Component {
state = {
adresse: "",
title: "",
description: "",
image: "",
greatImage: "",
price: 0,
nbPersons: 2,
loadigImg: false,
begin_date: moment(new Date(Date.now())).format("YYYY-MM-DD"),
end_date: moment(new Date(Date.now()))
.add(1, "days")
.format("YYYY-MM-DD")
};
With the Mutation call:
<Mutation
mutation={CREATE_ARTICLE_MUTATION}
variables={{
...this.state,
maxUserNumber: this.state.nbPersons,
street: this.state.adresse
}}
>
And the backendMutation:
async createArticle(parent, args, ctx, info) {
if (!ctx.request.userId) {
throw new Error("Vous devez être connecté");
}
const article = await ctx.db.mutation.createArticle(
{
data: {
user: {
connect: {
id: ctx.request.userId
}
},
...args
}
},
info
);
return article;
},
When I use my createArticle mutation I have an error that specified:
Reason 'end_date' field is not defined in the type
ArticleCreateInput
But, when I log the args on my mutation, I have all my fields!
As I understand this is a graphql runtime issue, therefore try to temporarily replace the DateTime type with either a string or a number (if you rely on an epoch). A possible problem is that you are using this non standard DateTime scalar, meaning you need a resolver to convert this custom type which one apollo will use to serialize it. If for some reason this converter is broken, it might return null or undefined which would produce the error you do have.
According to the error message, it seems to be you forgot to reference the Article model with another related model(s). In Prisma, you can use something similar to this: references: [id] and in GraphCMS find the Reference button on the Add Field menu on the top right.

Add an array of Objects to a mutation in apollo-react

I am using react-apollo on the front-end and graphcool on the backend. I have a mutation that creates a tutorial like so:
const CREATE_TUTORIAL_MUTATION = gql`
mutation CreateTutorialMutation(
$author: String
$link: String
$title: String!
$postedById: ID!
$completed: Boolean!
) {
createTutorial(
author: $author
link: $link
title: $title
postedById: $postedById
completed: $completed
) {
author
link
title
postedBy {
id
name
}
completed
}
}
`
It gets called in a submit handler like so...
this.props.createTutorialMutation({
variables: {
author,
link,
title,
completed: false,
postedById
}
})
Everything works wonderfully.
Now I want to add a set of tags to when I create a new tutorial. I created the input field and connected it so that the tags variable is an array of objects, each with a tag id and the tag text.
If I try and add the tags field to the mutation it needs a scalar type. But there is doesn't seem to be a scalar type for an array of objects.
If I pass the tag variable in as a parameter when I call the mutation how do I fill in the Scalar type field in the mutation ( on line 148 here https://github.com/joshpitzalis/path/blob/graphQL/src/components/Add.js) and in the schema?
I am new to graphQL and I understand that I might be approaching this completely the wrong way. If that is the case, how do I add an array of objects to a mutation in graphQL?
You should add a new Tag type to your schema file and connect it to Tutorial with a new relation:
type Tutorial {
author: String
completed: Boolean
link: String
title: String!
id: ID! #isUnique
createdAt: DateTime!
updatedAt: DateTime!
postedBy: User #relation(name: "UsersTutorials")
tags: [Tag!]! #relation(name: "TutorialTags")
}
type Tag {
id: ID!
tag: String!
number: Int!
tutorials: [Tutorial!]! #relation(name: "TutorialTags")
}
Then you can create a new tutorial and new tags using a nested create mutation like this:
const CREATE_TUTORIAL_MUTATION = gql`
mutation CreateTutorialMutation(
$author: String
$link: String
$title: String!
$tags: [TutorialtagsTag!]!
$completed: Boolean!
$postedById: ID!
) {
createTutorial(
author: $author
link: $link
title: $title
tags: $tags
completed: $completed
postedById: $postedById
) {
author
link
title
postedBy {
id
name
}
completed
tags {
id
text
}
}
}
`
This post gives more background about other approaches and their trade-offs: https://www.graph.cool/forum/t/how-do-i-add-an-array-of-objects-to-a-mutation-in-apollo-react/365/6?u=nilan
What i understand by your requirement is that if you have the following code
const user = {
name:"Rohit",
age:27,
marks: [10,15],
subjects:[
{name:"maths"},
{name:"science"}
]
};
const query = `mutation {
createUser(user:${user}) {
name
}
}`
you must be getting something like
"mutation {
createUser(user:[object Object]) {
name
}
}"
instead of the expected
"mutation {
createUser(user:{
name: "Rohit" ,
age: 27 ,
marks: [10 ,15 ] ,
subjects: [
{name: "maths" } ,
{name: "science" }
]
}) {
name
}
}"
If this is what you wanted to achieve, then gqlast is a nice tag function which you can use to get the expected result
Simply grab the js file from here and use it as:
const user = {
name:"Rohit",
age:27,
marks: [10,15],
subjects:[
{name:"maths"},
{name:"science"}
]
};
const query = gqlast`mutation {
createUser(user:${user}) {
name
}
}`
The result stored in the variable query will be :
"mutation {
createUser(user:{
name: "Rohit" ,
age: 27 ,
marks: [10 ,15 ] ,
subjects: [
{name: "maths" } ,
{name: "science" }
]
}) {
name
}
}"

Resources