awslabs / aws-mobile-appsync-sdk-js

JavaScript library files for Offline, Sync, Sigv4. includes support for React Native
Apache License 2.0
921 stars 267 forks source link

AppSync generated graphql subscription not running #339

Open cosinus84 opened 5 years ago

cosinus84 commented 5 years ago

Appsync generated graphql subscription is not working (tested using console). I think this is a big issue because when you start learning you expect at least generated things to work

//fails, generated by appsync subscription OnCreateNotes($id: ID, $title: String, $body: String) { onCreateNotes(id: $id, title: $title, body: $body) { id title body } }

//works subscription onNewCreateNotes { onNewCreateNotes { __typename id title body } }

haverchuck commented 5 years ago

@cosinus84 - Thanks for posting this issue. What is the error output you are receiving in the console?

cosinus84 commented 5 years ago

There is no error, simply in the second browser tab where the subscription is running (in aws appsync console), there is no response. On the first browser tab I am running in console: mutation createNotes($createnotesinput: CreateNotesInput!) { createNotes(input: $createnotesinput) { id title body } } //query variables { "createnotesinput": { "title": "The best note ever", "body": "This is the note that is the best note in my city" } }

cosinus84 commented 5 years ago

input CreateNotesInput { title: String body: String }

input DeleteNotesInput { id: ID! }

type Mutation { createNotes(input: CreateNotesInput!): Notes updateNotes(input: UpdateNotesInput!): Notes deleteNotes(input: DeleteNotesInput!): Notes }

type Notes { id: ID! title: String body: String }

type NotesConnection { items: [Notes] nextToken: String }

type Query { getNotes(id: ID!): Notes listNotes(filter: TableNotesFilterInput, limit: Int, nextToken: String): NotesConnection }

type Subscription { onCreateNotes(id: ID, title: String, body: String): Notes @aws_subscribe(mutations: ["createNotes"]) onNewCreateNotes: Notes @aws_subscribe(mutations: ["createNotes"]) onUpdateNotes(id: ID, title: String, body: String): Notes @aws_subscribe(mutations: ["updateNotes"]) onNewUpdateNotes: Notes @aws_subscribe(mutations: ["updateNotes"]) onDeleteNotes(id: ID, title: String, body: String): Notes @aws_subscribe(mutations: ["deleteNotes"]) }

input TableBooleanFilterInput { ne: Boolean eq: Boolean }

input TableFloatFilterInput { ne: Float eq: Float le: Float lt: Float ge: Float gt: Float contains: Float notContains: Float between: [Float] }

input TableIDFilterInput { ne: ID eq: ID le: ID lt: ID ge: ID gt: ID contains: ID notContains: ID between: [ID] beginsWith: ID }

input TableIntFilterInput { ne: Int eq: Int le: Int lt: Int ge: Int gt: Int contains: Int notContains: Int between: [Int] }

input TableNotesFilterInput { id: TableIDFilterInput title: TableStringFilterInput body: TableStringFilterInput }

input TableStringFilterInput { ne: String eq: String le: String lt: String ge: String gt: String contains: String notContains: String between: [String] beginsWith: String }

input UpdateNotesInput { id: ID! title: String body: String } This is generated by appsync when I created the project.

haverchuck commented 5 years ago

@cosinus84 What happens when you run the subscription without any values in the ()? So like this:

subscription {
   onCreateNotes {
      title
      body
   }
}  

Also (and excuse the silly question) you are clicking the run button on the console when you modify the subscription, yeah?

cosinus84 commented 5 years ago

subscription { onCreateNotes { title body } }
This works as expected. Hit run(second browser window), and is waiting. On the first browser tab hit run on create mutation and instant in the second tab the subscription receive the creation event.

In other words the generated creation subscription is not working with the params even if they are optional. But works well without any of params.

haverchuck commented 5 years ago

@cosinus84 - When you do use params, what are you using? From what I can tell, it kind of looks like you are trying to use all three properties from the Note object... which means the subscription will only be triggered when the created Note is identifical to what's in the subscription params, and if that's the case the subscription isn't necessarily needed.

cosinus84 commented 5 years ago

For example on IOS the params are optional, default to nil (null) so you can call the subscription without params

haverchuck commented 5 years ago

Can you give an example of an actual parameter value you are trying to use in a subscription when it is not working?

cosinus84 commented 5 years ago

screenshot 2019-01-17 at 23 39 15 screenshot 2019-01-17 at 23 34 09

subscription OnCreateNotes($id: ID, $title: String, $body: String) parameter are not with ! so they are optional, generated by appsync. When you start a project, appsync generates all for you.

cosinus84 commented 5 years ago

Even this is sdk-js, I don't think is any different then swift. All the code is generated by appsync automatically The images on my comment above shows that is not working not even in console.

public final class OnCreateNotesSubscription: GraphQLSubscription {
  public static let operationString =
    "subscription OnCreateNotes($id: ID, $title: String, $body: String) {\n  onCreateNotes(id: $id, title: $title, body: $body) {\n    __typename\n    id\n    title\n    body\n  }\n}"

  public var id: GraphQLID?
  public var title: String?
  public var body: String?

  public init(id: GraphQLID? = nil, title: String? = nil, body: String? = nil) {
    self.id = id
    self.title = title
    self.body = body
  }

listen for subscription in code

discard = try appSyncClient?.subscribe(subscription: OnCreateNotesSubscription(), resultHandler: { (result, transaction, error). Is not working (you can use empty constructor).

But it works with the following code.

public final class OnNewCreateNotesSubscription: GraphQLSubscription {
  public static let operationString =
    "subscription OnNewCreateNotes {\n  onNewCreateNotes {\n    __typename\n    id\n    title\n    body\n  }\n}"

  public init() {
  }
michael-b-willingham commented 5 years ago

Short explanation: I think the subscription in the screenshot is evaluating to onCreateNotes(id: null, title: null, body: null). Therefore, the subscription is looking for created Notes which have id = null, title = null, and body = null.

Longer Answer: The subscription has 3 query variables defined for the operation ($id, $title, and $body). Since id, title and body are defined and they are being used as input parameters to the subscription, the graphQL engine will try to coerce those values by looking into the Query Variables passed in (bottom left corner of the page). In the screenshot, there is a variable value for createnotesinput, but there are no variables passed in for id, title, or body. Therefore, a default value is probably inserted for id, title, and body. The default value, in this case, is probably null.

cosinus84 commented 5 years ago

I understand, but those params are not required so they should be ignored if are not present. If you look at the code generated you can call the constructor with no params, should work. I say is an issue.

haverchuck commented 5 years ago

@cosinus84 The params in the subscription would be ignored if the keys simply weren't present. But if you are including the keys but giving them a value of null, I believe the subscription would be listening for created objects with 'null' values.

cosinus84 commented 5 years ago

Yes this is true but they need a fix because code generated doesn't say such a thing. Or at least fix the created subscription, to be without params.

ArronHsiao commented 5 years ago

Same problem here, was this solved? I can't get anything as passing variables into subscribeToMore, even if I use undefined/null value, nothing happened.

I'm kind of wondering if the input different between mutation and subscription will cause error?

mutation --> createNotes(input: CreateNotesInput!): Notes subscription --> onCreateNotes(id: ID, title: String, body: String): Notes

jbesw commented 5 years ago

I can confirm this is still a problem in the console - the generated subscription syntax does not work properly, as the OP has described.

cosinus84 commented 5 years ago

Switched to flutter and firebase in the meantime (hope by 202x there will be some dart package from AWS). We are heavily using aws everywhere so I am still interested in appsync.

@haverchuck do you have any news about this issue?

munibrahman commented 5 years ago

Ok, so this is very annoying. I designed an entire API base on the pretence that if an argument's value is optional, it simply would be discarded from being passed into the resolver. (This is the case if you test your api with the web query panel).

Now, that I am starting to test my code with the iOS SDK. All of the optional values are being passed in as null. Which is really annoying because I have to find some sort of "hack" to get around this and implement it in every single resolver so far.

lawmicha commented 5 years ago

@returnzer0 which SDK are you using? https://github.com/awslabs/aws-mobile-appsync-sdk-ios or one from https://github.com/aws-amplify/aws-sdk-ios

The current issue posted sounds related to Appsync's default subscriptions not working. To better understand your issue with the iOS SDK, can you open an issue over in the repo you are using and provide more details? There will be a template there that will help us gather enough details

munibrahman commented 5 years ago

@lawmicha the first one.

I will do that promptly. Thanks

Opened issue.

kigorw commented 4 years ago

Hi, have the same issue. Very confused, you expect autogenerated code to work.

simform-solutions commented 4 years ago

Any update on this? I am facing this same issue.

chargome commented 4 years ago

Same here using the Amplify GraphQL Client. When I omit optional values I get no updates at all

slatemates commented 4 years ago

Faced a similar problem . The workaround is that you have to write a new subscription without the parameters that you are passing as null. You wont need to write any custom resolvers for it .

For example,

Lets say your onCreateType($param 1 string , $ param2) . If you pass param2 as null, you wont get any updates. You will need to write another subscription

onCreateType($param1 String) and then use this subscription in your code.

Hope it helps !

rawnsley commented 3 years ago

Faced a similar problem . The workaround is that you have to write a new subscription without the parameters that you are passing as null. You wont need to write any custom resolvers for it .

For example,

Lets say your onCreateType($param 1 string , $ param2) . If you pass param2 as null, you wont get any updates. You will need to write another subscription

onCreateType($param1 String) and then use this subscription in your code.

Hope it helps !

This seems to correlate with the advice in the Argument null value has meaning section which states:

When making a subscription query in AWS AppSync, a null argument value will filter the results differently than omitting the argument entirely.

JeetChhatrala commented 3 years ago

not working for me still, any workaround for this ?