amplify-swift
amplify-swift copied to clipboard
Listen in to a custom subscription within an AppSync schema
Is your feature request related to a problem? Please describe. Amplify for iOS currently does not seem to have the capability to create a subscription for a change besides the default Subscription handler for a Model object. What I would like is to be able to pass in inputs to filter my subscription by ID or by some other parameter.
This is the subscription I currently have set up in my schema. As you can see, it takes an ID as a parameter.
type Subscription {
onUpdate(id: ID!): Item
@aws_subscribe(mutations: ["updateItem"])
}
Describe the solution you'd like
I would like a way to specify the name of a subscription function and pass parameters into it before listening to it. I would like to see it as an optional parameter in the subscription enum for GraphQLRequest.
For what it's worth, I was able to find a work-around to accomplish this.
let request = GraphQLRequest(apiName: "myapi", document: "subscription { onUpdate(id: \"19dee48e-6daa-417d-a9b1-8d7108ab8735\") { id, conversionCount } }", variables: [:], responseType: JSONValue.self, decodePath: nil)
subscription = Amplify.API.subscribe(request: .subs, valueListener: { _ in
// do stuff
}, completionListener: nil)
Hi @benrosen78, thanks for the detailed solution. The Model types generated from amplify codegen models uses the graphql schema with types containing the @model directive, which is used in the GraphQL Transform (like when you run amplify add api, amplify push) to generate the
AppSync API and related resources. The extensions help build the GraphQLRequest for those APIs and do not currently take in optional inputs since there wasn't a clear requirement for it.
To identify the need for it, how did you provision the AppSync service? Through AppSync console? or was there a set of directives that you used that provisioned the subscription API withid as input?
The work-around is what we would expect for requests which need customization. You can also extract the variable out to dynamically inject it.
let variables = ["id": id] // `id` variable
let request = GraphQLRequest(apiName: "myapi", document: "subscription($id: ID!) { onUpdate(id: $id) { id, conversionCount } }", variables: variables, responseType: JSONValue.self, decodePath: nil)
subscription = Amplify.API.subscribe(request: .subs, valueListener: { _ in
// do stuff
}, completionListener: nil)
Also, is there a reason to use JSONValue as the response type over the Model type or a Codable type that matches your Item?
Your own docs specify the way to create custom subscriptions with arguments. Still this is categorised as iOS, the example code is in JavaScript: https://docs.amplify.aws/guides/api-graphql/subscriptions-by-id/q/platform/ios
Also adding the mentioned Subscription does only have the effect with amplify codegen models that two more files are created (Subscription.swift & Subscription+Schema.swift) which are basically empty
// swiftlint:disable all
import Amplify
import Foundation
We have multiple clients needed to subscribe to updates of their own data. In the moment every client gets every update and is missing a separation, so a default support would be greatly appreciated..
Your own docs specify the way to create custom subscriptions with arguments. Still this is categorised as iOS, the example code is in JavaScript: https://docs.amplify.aws/guides/api-graphql/subscriptions-by-id/q/platform/ios
Thanks for this link, the relevant piece that I missed in my earlier comment was that this
type Subscription {
onCommentByPostId(postCommentsId: ID!): Comment
@aws_subscribe(mutations: ["createComment"])
}
is actually placed in the schema used for GraphQLTransform. As for those docs categorized as iOS, that is something we need to address as well. I believe there just isn't a code snippet provided for the iOS platform so it shows JS for all of the platforms including Android as well.
Also adding the mentioned
Subscriptiondoes only have the effect withamplify codegen modelsthat two more files are created (Subscription.swift&Subscription+Schema.swift) which are basically empty// swiftlint:disable all import Amplify import FoundationWe have multiple clients needed to subscribe to updates of their own data. In the moment every client gets every update and is missing a separation, so a default support would be greatly appreciated..
This looks like an artifact of the fact that amplify codegen models has not handled this custom subscription use cases. A modification to the codesnippet above would be to continue to use the Model type as type to decode to, since the custom subscriptions are returning that type as well.
let variables = ["id": id] // `id` variable
let request = GraphQLRequest(document: "subscription($id: ID!) { onUpdate(id: $id) { id, conversionCount } }", variables: variables, responseType: Item.self, decodePath: nil)
subscription = Amplify.API.subscribe(request: .subs, valueListener: { _ in
// do stuff
}, completionListener: nil)
JSONValue.self -> Item.self .
I am encountering the same problem, and when I use the workaround I get a "Failed to decode GraphQL response to the 'ResponseType' Item Any help would be appreciated!
@LaszloDev Could you please open a new issue with details you mentioned in your comments?
Please track https://github.com/aws-amplify/docs/pull/5649 for the Upgrade Guide. Once we have this ready, the latest CLI will allow generating API.swift through amplify codegen types that is compatible with Amplify.API, thus custom subscriptions use case like this will be possible