Add auth to many to many Amplify GraphQL DataStore connection - graphql

I am beginning a project with Amplify DataStore and modeling data that has a many-to-many relationship that also requires authorization. I'm having a hard time finding examples of M2M with auth, there are none in the documentation.
Here is a MTM example from the DataStore docs, I want to prevent users that are not PostEditors from being able to load Posts. Currently the plan is to use Cognito, but open to other solutions. How would this be achieved?
type Post #model {
id: ID!
title: String!
editors: [PostEditor] #connection(keyName: "byPost", fields: ["id"])
}
type PostEditor
#model(queries: null)
#key(name: "byPost", fields: ["postID", "editorID"])
#key(name: "byEditor", fields: ["editorID", "postID"]) {
id: ID!
postID: ID!
editorID: ID!
post: Post! #connection(fields: ["postID"])
editor: User! #connection(fields: ["editorID"])
}
type User #model {
id: ID!
username: String!
posts: [PostEditor] #connection(keyName: "byEditor", fields: ["id"])
}

Related

AWS Amplify GraphQL Schema is causing an error

I am new to Amplify and I am trying to set up a fairly complex schema. When I run amplify push, the only response that I get is ...
An error occurred when pushing the resources to the cloud
This happens after the notice that it will create the resources and I am asked if I want to continue. I deleted most of the schema and tried again with just one model and it worked, so there is a problem somewhere in my schema ... I guess? I don't see anywhere to check it.
Here is the schema
type Article
#model
#key(name: "bySource", fields: ["sourceId", "dateWritten"]) {
id: ID!
link: AWSURL!
title: String!
dateWritten: String!
createdAt: String!
data: AWSJSON!
approved: Boolean!
admin: Boolean!
creatorId: ID!
creator: User #connection(fields: ["creatorId"])
sourceId: ID!
source: Source #connection(fields: ["sourceId"])
tagArtCons: [TagArtCon]
#connection(keyName: "byArticle", fields: ["articleId"])
}
type Tag #model #key(name: "byFrontPage", fields: ["frontpage"]) {
id: ID!
name: String!
createdAt: String!
creatorId: ID!
data: AWSJSON!
frontpage: String
official: Boolean!
tagArtConns: [TagArtCon] #connection(keyName: "byTag", fields: ["tagId"])
}
type TagArtCon
#model
#key(name: "byTag", fields: ["tagId"])
#key(name: "byArticle", fields: ["articleId"]) {
id: ID!
tagId: ID!
articleId: ID!
creatorId: ID!
createdAt: String!
article: Article #connection(fields: ["articleId"])
tag: Tag #connection(fields: ["tagId"])
parentRelations: [TagRelation]
#connection(keyName: "byParent", fields: ["tagId"])
childRelations: [TagRelation]
#connection(keyName: "byChild", fields: ["tagId"])
}
type TagRelation
#model
#key(name: "byParent", fields: ["parentId"])
#key(name: "byChild", fields: ["childId"]) {
id: ID!
parentId: ID!
childId: ID!
creatorId: ID!
createdAt: String!
parentTag: Tag #connection(fields: ["parentId"])
childTag: Tag #connection(fields: ["childId"])
}
type Source #model {
id: ID!
sourceName: String!
sourceUrl: String!
sourceImage: String!
creatorId: ID!
articles: [Article] #connection(keyName: "bySource", fields: ["id"])
}
type User #model {
id: ID!
userName: String!
userImage: String!
admin: Boolean!
createdAt: String!
data: AWSJSON
}
What I am trying to do is have a bunch of articles and a bunch of tags. The tags represent categories, people, etc. I have the following tables
articles,
tags,
a table where each entry ties an article to a tag
a table of relations between tags where parent/child relationships are held
a source table that just holds data for the sources of the articles
a user table
I've made a mistake somewhere and the schema isn't working and it isn't telling me why. I'm gonna keep simplifying this until I can hope to nail down the problem, but I would really appreciate any help as I am new to this. Thanks.
Finally found the problem(s). There is a place where I try to use "articleId" and a place where I try to use "tagId" and both should be "id".

How to model Many to Many relationship for Amplify GraphQL Schema on Same Table

I am using GraphQl API in an Amplify project and having some difficulty understanding how to model a many to many relationship between users. I get how to add a join table between two other tables. But now sure how to do it for the same table.
This is what I have but I'm almost certain it's not correct. I want each user to be able to add other Users as 'relations':
type User
#model
#auth(rules: [{ allow: owner, operations: [create, delete, update] }]) {
id: ID!
cognitoId: ID!
username: String!
registered: Boolean
contacts: [UserContacts] #connection(keyName: "byContact", fields: ["id"])
contactOfOtherUsers: [UserContacts] #connection(keyName: "byContact2", fields: ["id"])
}
type UserContacts
#model
#auth(rules: [{ allow: owner, operations: [create, delete, update] }])
#key(name: "byContact", fields: ["userID", "contactID"])
#key(name: "byContact2", fields: ["contactID", "userID"]) {
id: ID!
userID: ID!
contactID: ID!
user: User! #connection(fields: ["userID"])
contact: User! #connection(fields: ["contactID"])
}
I'm pretty new to Amplify and not really sure what approach to take.
What seems very wrong to me is the contactOfOtherUsers field in User. It is redundant but not sure how else to link the join table.
Maybe too late but this might work. Disclaimer: This would apply to Amplify GraphQL Transformer v1, which still works but it is deprecated as it was replaced by GraphQL Transformer v2
type User
#model
#auth(rules: [{ allow: owner}]) {
id: ID!
cognitoId: ID!
username: String!
registered: Boolean
contacts: [UserContact] #connection(keyName: "byContact", fields: ["id"])
}
type UserContact
#model
#auth(
rules: [
{ allow: owner }
{
allow: owner
ownerField: "contacts"
operations: [update, delete, read]
}
]
) #key(name: "byContact", fields: ["contactOneID", "contactTwoID"]){
id: ID!
contactOneID: ID!
contactTwoID: ID!
contactOne: User! #connection(fields: ["contactOneID"])
contactTwo: User! #connection(fields: ["contactTwoID"])
contacts: [ID]
}

Add many to many connection in amplify graphql

I have a time consuming problem and no idea what I can test more.
This is working, but I need the in Recruiter for positions an array. But then I have a many to many connection and nothing is working anymore. Is there a nice way to solve it?
Here is my code:
type Position #model #auth(rules: []) {
id: ID!
title: String!
candidates: [Candidate]! #connection(name: "PositionCandidates")
interestedRecruiters: [Recruiter]! #connection(name: "PositionRecruiter")
}
type Candidate #model #auth(rules: []) {
id: ID!
firstname: String!
lastname: String!
email: AWSEmail!
birthday: AWSDate!
position: Position! #connection(name: "PositionCandidates")
}
type Recruiter #model #auth(rules: []) {
id: ID!
firstname: String!
lastname: String!
email: AWSEmail!
birthday: AWSDate!
positions: Position! #connection(name: "PositionRecruiter")
}
thanks !
To work with many-to-many connections with amplify/app sync you have to create a 'Join' table (type). You can think of the join table as a table where you store the connections.
I didn't completely understand from your example what you wanted the result to be, so I'll try to explain with an alternate example:
Lets say you have a system where multiple users can be the creators of a document, and a user also can be one of the creators of multiple documents. To accomplish this you must create three dynamoDb tables (or three types is the schema).
type User #model {
id: ID!
name: String
documents: [UserDocument] #connection(name: "UserDocumentConnection")
}
type Document #model {
id: ID!
title: String
content: String
users: [UserDocument] #connection(name: "DocumentUserConnection")
}
type UserDocument #model {
id: ID!
user: User #connection(name: "UserDocumentConnection")
document: Document #connection(name: "DocumentUserConnection")
}
Then you have a table containing all your users, a table containing all your Documents, and a table containing all the connections between users and documents.
So let's say you have a users that is creating a new document. Then you first create the document, then when it is created and you have received the document back from appsync with the new id of the document, then you must create a new object in the UserDocument table, containing the id of the user and the id of the document. You can then also add more users on the document by adding more items to the UserDocument table.
I hope this will help you to the correct path forwards.

Query and Mutate GraphQL from Lambda function in AWS-Amplify using Cognito for auth

I created a GraphQL api via the amplify api add command and added the schema below. I'm using cognito for auth.
type User #model
#auth(rules: [{ allow: owner }]) {
id: ID!
videos: [Video!] #connection(keyName: "videosByUser", fields: ["id"])
adverts: [Advert] #connection(keyName:"advertsByUser", fields: ["id"])
}
type Video #model
#key(name: "videosByUser", fields: ["userId"])
#auth(rules: [{ allow: owner, operations: [create, update, delete] }]) {
id: ID!
title: String!
description: String!
size: Float!
length: Float!
hashMarks: [Float!]!
userId: ID!
# bidrectional connection, if needed
# user: User! #connection(fields: ["userId"])
adverts: [VideoAdverts!] #connection(keyName: "advertsByVideo", fields: ["id"])
streamingLink: AWSURL
}
type VideoAdverts #model(queries: null)
#key(name: "advertsByVideo", fields: ["videoId", "advertId"])
#key(name: "videosByAdvert", fields: ["advertId", "videoId"]) {
id: ID!
videoId: ID!
advertId: ID!
video: Video! #connection(fields: ["videoId"])
advert: Advert! #connection(fields: ["advertId"])
}
type Advert #model
#key(name: "advertsByUser", fields: ["userId"])
#auth(rules: [{ allow: owner, operations: [create, update, delete] }]) {
id: ID!
title: String!
description: String!
size: Float!
length: Float!
creatorId: ID!
# bidrectional connection, if needed
# creator: Creator! #connection(fields: ["creatorId"])
videos: [VideoAdverts!] #connection(keyName: "videosByAdvert", fields: ["id"])
blacklist: [AdvertBlacklist!] #connection(keyName: "blacklistByAdvert", fields: ["id"])
startDate: AWSDateTime
endDate: AWSDateTime
}
This is my first amplify project and I'm having trouble figuring out how to implement the following use cases:
Use a lambda function to query data and return to a client.
Use a cron triggered lambda function to make an API call and use a mutation to update some fields.
All I have found so far from googling involves using lambdas to interact with data added via the amplify storage add command.
A few other examples I found here on Stackoverflow do not use cognito for auth.
Looks like I will be able to use cloudwatch to trigger lambdas, and so my main problem now is how to actually query and mutate a GraphQL api from a lambda, using cognito for authentication.
Any help would be super helpful, thanks :)
The key to authenticating your Lambda functions to interact with your AppSync API is to configure multiple authentication methods. You are using Cognito for your front end application users, however, you do not want to use that for your Lambda function authentication. AppSync supports multiple authentications mechanisms for your API. In your case, you will want to add IAM as the second authentication mechanism.
You can do this from the Amplify CLI:
$ amplify update api
Scanning for plugins...
Plugin scan successful
? Please select from one of the below mentioned services: GraphQL
? Choose the default authorization type for the API Amazon Cognito User Pool
Use a Cognito user pool configured as a part of this project.
? Do you want to configure advanced settings for the GraphQL API Yes, I want
to make some additional changes.
? Configure additional auth types? Yes
? Choose the additional authorization types you want to configure for the API IAM

Error: Invalid AST Node: {"input":"** } on graphql mutation (Amplify client)

I tried to use example schema on api doc("https://aws-amplify.github.io/docs/cli-toolchain/graphql?sdk=js") like below on Many-To-Many Connections
type Post #model {
id: ID!
title: String!
editors: [PostEditor] #connection(keyName: "byPost", fields: ["id"])
}
# Create a join model and disable queries as you don't need them
# and can query through Post.editors and User.posts
type PostEditor
#model(queries: null)
#key(name: "byPost", fields: ["postID", "editorID"])
#key(name: "byEditor", fields: ["editorID", "postID"]) {
id: ID!
postID: ID!
editorID: ID!
post: Post! #connection(fields: ["postID"])
editor: User! #connection(fields: ["editorID"])
}
type User #model {
id: ID!
username: String!
posts: [PostEditor] #connection(keyName: "byEditor", fields: ["id"])
}
I created all items and then I tried to delete them but I failed especially on PostEditor.
There is a mutation to delete PostEditor so I called it like below
API.graphql(graphqlOperation((deletePostEditor, {input: {id},})))
It fails with below error message.
Error: Invalid AST Node: {"input":"b2f7064c-af32-49cd-8c87-*******"}
I think I provided right ID. I checked it on query.
You should pass your parameters as a second parameter of graphqlOperation. so , check your parentheses
API.graphql(graphqlOperation((deletePostEditor, {input: {id},}))),you have one pair extra parenthesis
below is correct one
API.graphql(graphqlOperation(deletePostEditor, { input: { id } }))
first param=deletePostEditor
second param={ input: { id } }
tiny mistake, Isn't It?

Resources