Filtering subscriptions by field types does not work for Angular generated API.service.ts
When defining subscription types for Angular there is no way to pass the defined parameter via the generated API
To Reproduce
Steps to reproduce the behavior:
Step 1: Define an entity and set subscriptions to null as per (https://docs.amplify.aws/cli/graphql-transformer/examples#filter-subscriptions-by-model-fields-andor-relations)
type ChangeSource @model(subscriptions: null) @auth(rules: [ { allow: groups, groupsField: "group"}])
{
id: ID!
group: String!
source: String!
action: Int!
target: String!
createdAt: String
}
amplify push
Then add the required subscription with the parameter to filter by
type Subscription {
onCreateChangeSource(group: String): ChangeSource @aws_subscribe(mutations: ["createChangeSource"])
}
amplify push
generates
OnCreateChangeSourceListener: Observable<
OnCreateChangeSourceSubscription
= API.graphql(
graphqlOperation(
subscription OnCreateChangeSource($group: String) { onCreateChangeSource(group: $group) { __typename id group source action target createdAt updatedAt } }
)
) as Observable;
What I canExpected behavior
The API should then allow for a call like
const subscription = this.apiService.OnCreateChangeSourceListener(grpName).subscribe({
next: (data) => console.log(data),
error: (error) => console.error(error)
})
However it does not provide a way to pass any parameters
Code Snippet
API only allows an unfiltered subscription
const subscription = this.apiService.OnCreateChangeSourceListener.subscribe({
next: (data) => console.log(data),
error: (error) => console.error(error)
})
What is Configured?
The configuration for Amplify CLI:
Environment
npx envinfo --system --binaries --browsers --npmPackages --npmGlobalPackages
System:
OS: macOS 10.15.7
CPU: (4) x64 Intel(R) Core(TM) i5-5257U CPU @ 2.70GHz
Memory: 147.73 MB / 8.00 GB
Shell: 3.2.57 - /bin/bash
Binaries:
Node: 12.13.1 - /usr/local/bin/node
npm: 6.14.8 - /usr/local/bin/npm
Browsers:
Brave Browser: 86.1.16.68
Chrome: 86.0.4240.198
Firefox: 79.0
Safari: 14.0
npmPackages:
@angular-devkit/build-angular: ~0.803.20 => 0.803.25
@angular/animations: ~8.2.14 => 8.2.14
@angular/cdk: ~8.2.3 => 8.2.3
@angular/cli: ~8.3.23 => 8.3.25
@angular/common: ~8.2.14 => 8.2.14
@angular/compiler: ~8.2.14 => 8.2.14
@angular/compiler-cli: ~8.2.14 => 8.2.14
@angular/core: ~8.2.14 => 8.2.14
@angular/forms: ~8.2.14 => 8.2.14
@angular/language-service: ~8.2.14 => 8.2.14
@angular/material: ^8.2.3 => 8.2.3
@angular/platform-browser: ~8.2.14 => 8.2.14
@angular/platform-browser-dynamic: ~8.2.14 => 8.2.14
@angular/router: ~8.2.14 => 8.2.14
@capacitor/cli: 1.5.0 => 1.5.0
@capacitor/core: 1.5.0 => 1.5.0
@ionic-native/core: ^5.0.0 => 5.21.6
@ionic-native/splash-screen: ^5.0.0 => 5.21.6
@ionic-native/status-bar: ^5.0.0 => 5.21.6
@ionic/angular: ^5.0.0 => 5.0.1
@ionic/angular-toolkit: ^2.1.1 => 2.1.2
@react-native-community/netinfo: ^5.9.7 => 5.9.7
@syncfusion/ej2-angular-charts: ^18.1.52 => 18.1.52
@syncfusion/ej2-angular-gantt: ^18.1.48 => 18.1.48
@syncfusion/ej2-angular-schedule: ^18.2.47 => 18.2.47
@types/jasmine: ~3.3.8 => 3.3.16
@types/jasminewd2: ~2.0.3 => 2.0.8
@types/node: ~8.9.4 => 8.9.5
aws-amplify: ^3.3.2 => 3.3.2
aws-sdk: ^2.760.0 => 2.760.0
codelyzer: ^5.0.0 => 5.2.1
core-js: ^2.5.4 => 2.6.11
hammerjs: ^2.0.8 => 2.0.8
jasmine-core: ~3.4.0 => 3.4.0
jasmine-spec-reporter: ~4.2.1 => 4.2.1
karma: ~4.1.0 => 4.1.0
karma-chrome-launcher: ~2.2.0 => 2.2.0
karma-coverage-istanbul-reporter: ~2.0.1 => 2.0.6
karma-jasmine: ~2.0.1 => 2.0.1
karma-jasmine-html-reporter: ^1.4.0 => 1.5.2
ngx-quill: ^8.0.0 => 8.0.0
protractor: ~5.4.0 => 5.4.3
quill: ^1.3.7 => 1.3.7
quill-blot-formatter: ^1.0.5 => 1.0.5
quill-emoji: ^0.1.8 => 0.1.8
quill-image-drop-module: ^1.0.3 => 1.0.3
quill-image-resize-module: ^3.0.0 => 3.0.0
rxjs: ~6.5.1 => 6.5.4
serverless-domain-manager: ^3.3.1 => 3.3.1
stripe: ^8.24.0 => 8.24.0
ts: ^0.2.2 => 0.2.2
ts-node: ~7.0.0 => 7.0.1
tslib: ^1.9.0 => 1.11.0
tslint: ~5.15.0 => 5.15.0
typescript: ~3.5.1 => 3.5.3
zen-observable: ^0.8.15 => 0.8.15
zen-observable-ts: ^0.8.21 => 0.8.21
zone.js: ~0.9.1 => 0.9.1
npmGlobalPackages:
@angular/cli: 1.0.0
@aws-amplify/cli: 4.29.3
@ionic/cli-plugin-ionic-angular: 1.3.0
@ionic/cli: 6.11.8
bower: 1.8.0
cordova: 7.0.1
create-react-app: 1.4.3
firebase-tools: 4.2.1
gcloud: 0.37.2
ios-deploy: 1.9.1
ios-sim: 4.1.1
javascript-qrcode: 1.0.7
mocha: 3.5.0
n: 2.1.4
nativescript: 2.2.1
nodemon: 1.18.4
npm: 6.14.8
qrcode-svg: 1.0.0
react-create-app: 2.0.6
serverless: 1.79.0
to: 0.2.9
uglify-js: 2.7.5
uglifyjs: 2.4.10
update: 0.7.4
util: 0.10.3
xcodeproj: 0.0.0
Smartphone (please complete the following information):
Additional context
Add any other context about the problem here.
_You can turn on the debug mode to provide more info for us by setting window.LOG_LEVEL = 'DEBUG'; in your app._
Hmm maybe it is meant to work like this
this.apiservice.OnCreateChangeSourceListener.filter(this.group).subscribe({
next: (data) => console.log(data)
});
Late now, try it out tomorrow
Hey @markeames, you're correct that it's not currently possible to pass subscription arguments using API.service.ts, however, you can create a custom subscription listener using the API category:
import { API, graphqlOperation } from 'aws-amplify;
const onCreateChangeSourceListenerArgs = (group) => API.graphql(
graphqlOperation(
`subscription OnCreateChangeSource($group: String) {
onCreateChangeSource(group: $group) {
__typename
id
group
source
action
target
createdAt
updatedAt
}
}`
),
{ group: group }
)
function fn() {
const subscription = onCreateChangeSourceListenerArgs(this.group).subscribe({
next: (data) => console.log(data),
error: (error) => console.error(error)
});
}
Alternatively, you can re-configure codegen to generate typescript files instead of an angular service. The typescript files allow more flexibility around graphql operations. For example:
$ amplify configure codegen
? Choose the code generation language target typescript
Followed by
$ amplify codegen
You can then use the subscriptions this way:
import { API, graphqlOperation } from 'aws-amplify;
import { onCreateChangeSource } from '../graphql/subscriptions';
const subscription = API.graphql(
graphqlOperation(onCreateChangeSource, { group: this.group })
).subscribe({
next: (data) => console.log(data),
error: (error) => console.error(error),
});
The workaround is to use Amplify API and graphOperation
import { API, graphqlOperation } from 'aws-amplify;
import { onCreateChangeSource } from '../graphql/subscriptions';
const subscription = API.graphql(
graphqlOperation(onCreateChangeSource, { group: this.group })
).subscribe({
next: (data) => console.log(data),
error: (error) => console.error(error),
});
While this works, the issue would be nice to see fixed, as once you have developed a whole bunch of front end code using the generated APIService, it is a bit of drag to have go back and refactor everything to use the Amplify API and graphqlOperation.
Plus there seems to be reported typescript issues with those.
@markeames that's fair. I'll transfer this over to the Amplify CLI team, as they manage the codegen functionality.
Thanks for looking into this! +1 for having parameterized subscriptions as part of the generated API service.
@iartemiev Thank you for your solution. But I have a question related to this line:
const subscription = onCreateChangeSourceListenerArgs(this.group).subscribe({
I get the following error:
Property 'subscribe' does not exist on type 'Promise<GraphQLResult<object>> | Observable<object>'
@iartemiev Thank you for your solution. But I have a question related to this line:
const subscription = onCreateChangeSourceListenerArgs(this.group).subscribe({I get the following error:
Property 'subscribe' does not exist on type 'Promise<GraphQLResult<object>> | Observable<object>'
@andre-scheffer Sounds like a typescript type-checking error. You should be able to do
const obs = onCreateChangeSourceListenerArgs(this.group) as Observable<object>;
const subscription = obs.subscribe({..});
You can also fill in <object> with a more specific type to get better autocompletion. I thiiink you can also do
const obs = onCreateChangeSourceListenerArgs(this.group);
if(obs instanceof Observable<object>) {
const subscription = obs.subscribe({..});
}
for more rigid type-checking.