Amplify-cli: No way to pass subscription parameters to Angular generated API

Created on 17 Nov 2020  路  7Comments  路  Source: aws-amplify/amplify-cli

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
}

  1. amplify push

  2. Then add the required subscription with the parameter to filter by
    type Subscription {
    onCreateChangeSource(group: String): ChangeSource @aws_subscribe(mutations: ["createChangeSource"])
    }

  3. 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:

  • Auth (Cognito User Pools), API (Rest, GraphQL and Storage (s3) configured.
  • amplify cli 4.29.3 and Angular 8.2.x


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):

  • Device: [e.g. iPhone6]
  • OS: [e.g. iOS8.1]
  • Browser [e.g. stock browser, safari]
  • Version [e.g. 22]

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._

DataStore code-gen

All 7 comments

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.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

ffxsam picture ffxsam  路  3Comments

gabriel-wilkes picture gabriel-wilkes  路  3Comments

adriatikgashi picture adriatikgashi  路  3Comments

nicksmithr picture nicksmithr  路  3Comments

rehos picture rehos  路  3Comments