I created a schema using the amplify cli and everything works as expected. The problem is when i try to perform a query on the events model it brings back comments as being null even though the event has comments. What confuses me more is when i query the comments alone they bring back their respective events but same thing does not work when i query for events. This is my schema below:
type Event #model {
id: ID!
title: String!
latitude: Float!
longitude: Float!
startDate: String!
endDate: String!
description: String!
coverUrl: String!
locationName: String!
Owner: User! #connection
attendies: [User!] #connection
photos: [Photo]
organization: Organization
comments: [Comment] #connection
}
type Comment #model {
id: ID!
user: User! #connection
event: Event! #connection
text: String!
}
The queries i performed are:
List Events
query listEvents {
listEvents {
items {
title
Owner {
username
}
comments {
items{
text
}
}
}
}
}
which brings back:
{
"data": {
"listEvents": {
"items": [
{
"title": "second Event",
"Owner": {
"username": "likono"
},
"comments": {
"items": []
}
}
]
}
}
}
and List Comments
query listComment{
listComments{
items{
text
event {
title
id
}
}
}
}
which brings back
{
"data": {
"listComments": {
"items": [
{
"text": "Second Comment Same User Same Event",
"event": {
"title": "second Event",
"id": "8bd6656b-b307-4e8f-ba65-84f75a4c2298"
}
}
]
}
}
}
Any help will be appreciated. Thanks.
Related
So I am currently playing with AWS AppSync and Amplify, and all is good except, with the new Transformer V2, I am struggling to get things to work.
Here's my schema:
type Post
#model
#auth(
rules: [
{ allow: owner, ownerField: "username" }
{ allow: public, operations: [read] }
]
) {
id: ID!
title: String!
content: String!
username: String
#index(name: "postsByUsername", queryField: "postsByUsername")
coverImage: String
comments: [Comment] #hasMany
}
type Comment
#model
#auth(
rules: [
{ allow: owner, ownerField: "createdBy" }
{ allow: public, operations: [read] }
]
) {
id: ID!
message: String
}
I can create a post and a comment. However, whenever I query a list of posts, I never get comments.
Here's an example of a query:
query MyQuery {
listPosts {
items {
comments {
items {
id
message
createdAt
}
}
content
title
username
}
}
}
and here's the corresponding result I get:
{
"data": {
"listPosts": {
"items": [
{
"comments": {
"items": []
},
"content": "Testing stuff",
"title": "Today is the day",
"username": "bawp"
},
{
"comments": {
"items": []
},
"content": "### hello\n````\n function call()\n```",
"title": "next item of the day",
"username": "paulod"
},
{
"comments": {
"items": []
},
"content": "Hello Word",
"title": "santo dia",
"username": "paulod"
}
]
}
}
}
Notice how the
"comments": {
"items": []
},
It is always empty!
Even though, when I query the Comments table, I get at least one comment added.
query MyQuery {
listComments {
items {
id
message
createdBy
}
}
}
Result:
{
"data": {
"listComments": {
"items": [
{
"id": "ddddf58b-df1c-498c-97b4-6d61361b4b9e",
"message": "Thjis is may coment here\n\n```\nCode could go here also!\n```",
"createdBy": "paulod"
}
]
}
}
}
I am not sure what I am missing here. Remember I am using new directives (Transformer v2) as opposed to the old relationship directives like
#connection
Any help is greatly appreciated.
Thank you very much!
Okay, this is a response to my question for anyone who might run into some of these issues.
Firstly,
The schema!
Since I am adding some relationships between the tables, the directives must be added correctly. Here are the changes I made to my schema:
type Post
#model
#auth(
rules: [
{ allow: owner, ownerField: "username" }
{ allow: public, operations: [read] }
]
) {
id: ID!
title: String!
content: String!
username: String
#index(name: "postsByUsername", queryField: "postsByUsername")
coverImage: String
comments: [Comment] #hasMany(indexName: "byPost", fields: ["id"]) #check out: https://docs.amplify.aws/cli/graphql/data-modeling/#has-many-relationship
}
#Comment
#queries: null - removes any authorization rules for queries, allowing anyone to query for comments
#ownerField:createdBy - sets the createdBy field as the currently signed in user
type Comment
#model
#auth(
rules: [
{ allow: owner, ownerField: "createdBy" }
{ allow: public, operations: [read] }
]
) {
id: ID!
message: String
post: Post #belongsTo(fields: ["postID"])
postID: ID #index(name: "byPost")
}
Next, because appsync autogenerates the queries.js file on each push, I had to edit this file manually (which is not really a final solution). In particular, the listPosts query:
export const listPosts = /* GraphQL */ `
query ListPosts(
$filter: ModelPostFilterInput
$limit: Int
$nextToken: String
) {
listPosts(filter: $filter, limit: $limit, nextToken: $nextToken) {
items {
id
title
content
username
coverImage
comments {
items {
id
message
postID
createdAt
updatedAt
createdBy
}
}
createdAt
updatedAt
}
nextToken
}
}
`;
You see, when this file is autogenerated, it would have "nextToken" instead of having fields that I wanted to query. In other words, the comments field would have { nextToken }
So, the query would look like this:
export const listPosts = /* GraphQL */ `
query ListPosts(
$filter: ModelPostFilterInput
$limit: Int
$nextToken: String
) {
listPosts(filter: $filter, limit: $limit, nextToken: $nextToken) {
items {
id
title
content
username
coverImage
comments {
nextToken # --> this is what was autogenerated, which was giving me issues!!!
}
createdAt
updatedAt
}
nextToken
}
}
`;
Once I changed nextToke with what I showed you earlier in the post, it all worked perfectly.
Now, I know that changing this file manually doesn't seem right. However, I am not in the process of figuring out a better way to do this.
But for now, that's what I was able to come up with.
I hope this helps somebody running into similar issues.
Thank you!
I have applied the schema just like you did in the answer, but also made the postId field important.
I think that has helped get the nested comments.
type Post
#model
#auth(
rules: [
{ allow: owner, ownerField: "username" }
{ allow: public, operations: [read] }
{ allow: private, operations: [read] }
]
) {
id: ID!
title: String!
content: String!
username: String
#index(name: "postsByUsername", queryField: "postsByUsername")
coverImage: String
comments: [Comment] #hasMany(indexName: "byPost", fields: ["id"]) #check out: https://docs.amplify.aws/cli/graphql/data-modeling/#has-many-relationship
}
#Comment
#queries: null - removes any authorization rules for queries, allowing anyone to query for comments
#ownerField:createdBy - sets the createdBy field as the currently signed in user
type Comment
#model
#auth(
rules: [
{ allow: owner, ownerField: "createdBy" }
{ allow: public, operations: [read] }
{ allow: private, operations: [read] }
]
) {
id: ID!
message: String
post: Post #belongsTo(fields: ["postID"])
postID: ID! #index(name: "byPost")
}
I'm not sure if I'm doing this correctly with the connections in AppSync GraphQL.
This is what my graphql models look like:
type User #model #auth(rules: [{ allow: owner, ownerField: "username" }]) {
id: ID!
username: String!
email: String!
userType: UserType
}
enum UserType {
TEACHER
CREATOR
}
type Teacher #model {
id: ID!
userId: ID
name: String!
activations: [Activation]
#connection(keyName: "activationsByTeacherId", fields: ["id"])
creators: [TeacherCreatorPartnership]
#connection(name: "TeacherCreatorPartnership")
}
type Creator #model {
id: ID!
userId: ID
name: String!
email: String!
username: String
teachers: [TeacherCreatorPartnership] #connection(name: "CreatorTeacherPartnership")
posts: [Post] #connection(name: "CreatorPosts")
activations: [CreatorActivations] #connection(name: "CreatorActivations")
}
type TeacherCreatorPartnership #model(queries: null) {
id: ID!
teacher: Teacher! #connection(name: "TeacherCreatorPartnership")
creator: Creator! #connection(name: "CreatorTeacherPartnership")
}
type CreatorActivations #model(queries: null) {
id: ID!
creator: Creator! #connection(name: "CreatorActivations")
activation: Activation! #connection(name: "ActivationCreators")
}
type Activation
#model
#key(
name: "activationsByTeacherId"
fields: ["teacherId"]
queryField: "activationsByTeacherId"
)
#auth(
rules: [
{ allow: groups, groups: ["Admin"] }
{
allow: owner
ownerField: "teacherId"
operations: [create, update, delete]
}
{ allow: private, operations: [read] }
{ allow: public, operations: [read] }
]
) {
id: ID!
teacherId: ID!
title: String!
teacher: Teacher #connection(fields: ["teacherId"])
creators: [CreatorActivations] #connection(name: "ActivationCreators")
}
The idea is that when user signs in with Amplify, they'll go through an onboarding process and choose whether they're a creator or a teacher.
This works fine, but the problem is if a signed-in user wants to create a new Activation.
I'm not sure if the graphql on the Activation model is set correctly, perhaps the auth key is wrong?
This is how I'm processing create
const createNewActivation = async () => {
if (!title || !content || !location) return;
const newId = uuid();
activation.id = newId;
const user = await Auth.currentAuthenticatedUser();
try {
await API.graphql({
query: createActivation,
variables: {
input: {
...activation,
teacherId: user.attributes.sub,
},
},
authMode: "AMAZON_COGNITO_USER_POOLS",
});
} catch (error) {
console.log("Error: problem creating activation: ", error);
}
};
I've also set up a lambda function so that when user confirms their account from sign up, it will save the user information in DynamoDB with an ID, the username, and email.
Edit: Got it working but...
So, I was able to save the data, but I had to change the schema in my Activation model from:
{
allow: owner
ownerField: "teacherId"
operations: [create, update, delete]
}
to just
{
allow: owner
}
Not sure why I can't set the owner to teacherId? Wouldn't I need this so I can make proper connections to Teacher's model with teachId field?
I've been following the AWS GraphQL CLI guide for setting up an API for my app, but am having trouble with connections.
The following is my current Graphql schema, with some attributes removed
type Employee #model {
id: ID!
employment: [Employment!] #connection(name: "byEmployeeIDByCompanyID", fields: ["id"])
}
type Company #model {
id: ID!
employees: [Employment!] #connection(name: "byCompanyIDByDateHired", fields: ["id"])
}
type Employment #model
#key(name: "byEmployeeIDByCompanyID", fields: ["employeeID", "companyID"], queryField: "employmentByEmployeeIDByCompanyID") {
id: ID!
companyID: ID!
employeeID: ID!
company: Company! #connection(fields: ["companyID"])
employee: Employee! #connection(fields: ["employeeID"])
}
When I query Employees or Companys, [Employment] always returns an empty array. Do I need to edit the resolvers for these fields? They should work out of the box, no?
From my understanding, using #key with 'name' and multiple 'fields' creates a secondary index on the table, and specifying that key with #connection tells the connection to use that key instead of the tables primary index. In the "byEmployeeIDByCompanyID" key, for example, employeeID is the partition key, and companyID is the sort key. A query on the "employmentByEmployeeIDByCompanyID" queryField with an employeeID but no companyID returns all the employments for a given employee, which is what I want, so why isn't the connection working?
I found success in editing the resolvers, so I'm going to go with this for now. For Employee.employment, I added:
"index": "byEmployeeIDByCompanyID",
to the request mapping template, and changed the query from:
{
"expression": "#partitionKey = :partitionKey",
"expressionNames": {
"#partitionKey": "id"
},
"expressionValues": {
":partitionKey": {
"S": "$context.source.id"
}
}
}
to
{
"expression": "#partitionKey = :partitionKey",
"expressionNames": {
"#partitionKey": "employeeID"
},
"expressionValues": {
":partitionKey": {
"S": "$context.source.id"
}
}
}
I am new to using amplify with GraphQL. I was setting up my DB schema and auto-generating the functions after running amplify push.
Goals I want to achieve but do not know how to are
I would like to be able to get user with all connected information (with one to one and one to many relationships) in the returned object from getUser
I would like to still be able to get userByUserName and see all connected one-to-many relationships as well
When calling the API generated function to get the user,
let user = await API.graphql(graphqlOperation(getUser,{id:userId}))
I am getting a user object back, however, it looks like this - even though I am definitely sure that data is set up correctly in the database.
buttons: {nextToken: null} -- WANT THIS TO INCLUDE ACTUAL INFORMATION ABOUT BUTTONS CONNECTED TO THIS USER
createdAt: "2020-09-02T23:41:12.278Z"
customStyles: {id: "e3d1bbef-ec6f-4a6d-9b5d-e693e890d4e0", bgColor: "F9FF9F", bgBtnColor: "FFFFFF", bgBtnHoverColor: "000000", textColor: "000000", …}
defaultStyles: null
email: "nata#email.edu"
firstName: "Nata"
id: "d683a6bb-383e-4cf1-943a-05b3da4e5cc3"
lastName: "Vache"
socialNetwork: {nextToken: null} -- WANT THIS TO INCLUDE ACTUAL INFORMATION ABOUT SOCIAL NETWORKS CONNECTED TO THIS USER, THE SAME WAY AS FOR EXAMPLE customStyles IS SHOWN.
updatedAt: "2020-09-02T23:41:12.278Z"
userName: "Nata568"
type User #model #key(name: "byUserName", fields: ["userName"], queryField: "userByUserName"){
id: ID!
firstName: String!
lastName: String!
userName: String!
email: String!
socialNetwork: [UserSocialNetwork] #connection(keyName: "UserSocialNetworkUser", fields: ["id"])
buttons: [Button] #connection(keyName: "ButtonUser", fields: ["id"])
defaultStyles: DefaultStyle #connection
customStyles: CustomStyle #connection
}
type UserSocialNetwork #model #key(name: "UserSocialNetworkUser", fields: ["userID", "id"], queryField:"userSocialNetworkByUserID") {
id: ID!
socialNetworkUsername: String!
userID: ID!
supportedSocialNetwork: SupportedSocialNetwork! #connection
}
type SupportedSocialNetwork #model {
id: ID!
name: String!
address: String!
}
type Button #model #key(name: "ButtonUser", fields: ["userID", "id"], queryField: "buttonByUserID") {
id: ID!
name: String!
address: String!
image: String
userID: ID!
}
This schema does not include all my model definitions - customStyles, defaultStyles, and the rest but they are one to one relationship, which is working perfectly fine. I am having issues with one-to-many relationships, such as User to UserSocialNetwork and User to Buttons.
I have read lots of resources about this on AWS Amplify Docs, have gone through examples but still have not found anything that I could work with that would allow me to get the information from connections on getUser call and also give me the ability to get the user by username.
Any input would be appreciated!!!
This is a problem with query Depth. It is 2 by default and need to increase it (to 4 in your case).
You can resolve this by following below steps.
In your cmd in your project root, (where you normally run amplify commands).
Run amplify codegen configure - This will prompt configs again.
Enter 4 for this option Enter maximum statement depth [increase from default if your schema is deeply nested]
Run amplify codegen - this will create your queries and mutations according to the new depth.
You can verify it by checking grapgql/queries.js.
Earlier you could see below fragment in getUser query in grapgql/queries.js,
buttons {
nextToken
}
But after following above resolution steps, it should be something like below.
buttons {
items {
id
image
address
}
}
Finally query for your user again.
General comment: If username is unique you could use that as the id instead of creating the extra index. If it isn't there will be problems with this schema since it can't do a getOperation but instead will do a query which might return multiple answers.
(The resolver in Appsync wants to use a dynamoDB.get by default (& design) but using an index would be a dynamoDB.query which results in a lot issues)
Anyway using your schema I can get it to work just fine when using the id
"data": {
"getUser": {
"createdAt": "2020-09-07T13:54:23.440Z",
"email": "meax",
"firstName": "Max",
"id": "19a752ec-5050-4e02-8ff8-05d9523e7ea5",
"socialNetwork": {
"items": [
{
"socialNetworkUsername": "What",
"id": "280ec8ea-5b25-46d3-8f22-f170e3210146",
"userID": "19a752ec-5050-4e02-8ff8-05d9523e7ea5"
}
]
},
"lastName": "Sc",
"userName": "zanndo",
"updatedAt": "2020-09-07T13:54:23.440Z",
"buttons": {
"items": [
{
"id": "65971568-b388-40a3-b99e-1bff0a730161",
"image": null,
"address": "ButonAdre"
}
]
}
}
}
}
This being my query
getUser(id: "19a752ec-5050-4e02-8ff8-05d9523e7ea5") {
createdAt
email
firstName
id
socialNetwork {
items {
socialNetworkUsername
id
userID
}
}
lastName
userName
updatedAt
buttons {
items {
id
image
address
}
}
}
}
Here is one where I made email the id.
query MyQuery {
getUser(id: "sw#gmail.com") {
id
firstName
lastName
socialNetwork {
items {
socialNetworkUsername
supportedSocialNetwork {
name
id
address
}
}
}
buttons {
items {
id
address
name
}
}
}
}
Also works
{
"data": {
"getUser": {
"id": "sw#gmail.com",
"firstName": "S",
"lastName": "W",
"socialNetwork": {
"items": [
{
"socialNetworkUsername": "SomeUserNameOrSomething",
"supportedSocialNetwork": {
"name": "Supported1",
"id": "daf52246-4b25-402c-9fdd-46f8f35e1b89",
"address": "SupportedAddr"
}
}
]
},
"buttons": {
"items": [
{
"id": "9883bd91-a2f1-479d-ab65-7a4bbe7b2dc4",
"address": "ButtonAddr",
"name": "Button1"
}
]
}
}
}
}
Bonus using your index
userByUserName(userName: "SW") {
items {
buttons {
items {
name
id
}
}
socialNetwork {
items {
socialNetworkUsername
supportedSocialNetwork {
name
}
}
}
}
}
"userByUserName": {
"items": [
{
"buttons": {
"items": [
{
"name": "Button1",
"id": "9883bd91-a2f1-479d-ab65-7a4bbe7b2dc4"
}
]
},
"socialNetwork": {
"items": [
{
"socialNetworkUsername": "SomeUserNameOrSomething",
"supportedSocialNetwork": {
"name": "Supported1"
}
}
]
}
}
]
}
This was the schema I used
type User #model #key(name: "byUserName", fields: ["userName"], queryField: "userByUserName"){
firstName: String!
lastName: String!
userName: String!
id: String!
socialNetwork: [UserSocialNetwork] #connection(keyName: "UserSocialNetworkUser", fields: ["id"])
buttons: [Button] #connection(keyName: "ButtonUser", fields: ["id"])
}
type UserSocialNetwork #model #key(name: "UserSocialNetworkUser", fields: ["userID", "id"], queryField:"userSocialNetworkByUserID") {
id: ID!
socialNetworkUsername: String!
userID: String!
supportedSocialNetwork: SupportedSocialNetwork! #connection
}
type SupportedSocialNetwork #model {
id: ID!
name: String!
address: String!
}
type Button #model #key(name: "ButtonUser", fields: ["userID", "id"], queryField: "buttonByUserID") {
id: ID!
name: String!
address: String!
image: String
userID: String!
}
Maybe I have misunderstood something?
I'm following a tutorial (here:https://www.howtographql.com/graphql-js/5-authentication/) on graphql and came across a mutation with nested inputs.
How would I write the corresponding graphql-tag?
gql``
Schema:
type Mutation {
createUser(name: String!, authProvider: AuthProviderSignupData!): User
}
###########
## Inputs
###########
input AuthProviderEmail {
email: String!
password: String!
}
input AuthProviderSignupData {
email: AuthProviderEmail
}
Corresponding graphiql input:
mutation CreateUser {
createUser(name: "tester2", authProvider: {email: {email: "test#test.com", password: "password"}}) {
id
name
}
}
const mutation = gql`
mutation createUser($authProvider: AuthProviderSignupData!, $name: String!) {
createUser(authProvider: $authProvider, name: $name) {
id
}
}
`
const variables = {
"authProvider": {
"email": {
"email": "chakri#example.com",
"password": "123456789"
}
},
"name": "chakri",
}