How can I resolve the issue of being unable to utilize the codegen auto-generated AppSync API code in my Amplify Angular application?
Discussed in https://github.com/aws/aws-appsync-community/discussions/367
Originally posted by saidberk27 August 14, 2024 I am relatively new to AWS and Angular development. I am currently working on a project where AWS IoT sends data to a specific topic, which triggers a Lambda function. This Lambda function then stores the data in DynamoDB, and my AppSync API reads from this DynamoDB table.
Objective: My goal is to create a real-time IoT web application. Specifically, I want to frequently check DynamoDB for any updates, as I expect changes to occur approximately six times per minute due to the IoT device's activity.
Current Progress: I have tested my AppSync API, and it successfully reacts to new data published to the IoT channel. I can see the newly added item's partition key (though not the full data), indicating that the API is responsive to IoT events.
Issue: I am encountering difficulties when attempting to integrate this API with my Angular 18 application, which is built using AWS Amplify.
I have followed the documentation to configure my application, as shown below:
// app.config.ts
Amplify.configure(outputs); // For auth and data
Amplify.configure({
API: {
GraphQL: {
endpoint: 'https://xxx.appsync-api.xx-xx-2.amazonaws.com/graphql',
region: 'xx-xx-2',
defaultAuthMode: 'apiKey',
apiKey: 'da2-xxx'
}
}
});
Subsequently, I used the codegen feature to generate a service file for my API.
/* tslint:disable */
/* eslint-disable */
// This file was automatically generated and should not be edited.
import { Injectable } from "@angular/core";
import { Client, generateClient, GraphQLResult } from "aws-amplify/api";
import { Observable } from "rxjs";
export type __SubscriptionContainer = {
onCreateIotTest: OnCreateIotTestSubscription;
onUpdateIotTest: OnUpdateIotTestSubscription;
onDeleteIotTest: OnDeleteIotTestSubscription;
};
export type CreateIotTestInput = {
iot_test: string;
};
export type IotTest = {
__typename: "IotTest";
iot_test: string;
};
export type UpdateIotTestInput = {
iot_test: string;
};
export type DeleteIotTestInput = {
iot_test: string;
};
export type TableIotTestFilterInput = {
iot_test?: TableStringFilterInput | null;
};
export type TableStringFilterInput = {
ne?: string | null;
eq?: string | null;
le?: string | null;
lt?: string | null;
ge?: string | null;
gt?: string | null;
contains?: string | null;
notContains?: string | null;
between?: Array<string | null> | null;
beginsWith?: string | null;
attributeExists?: boolean | null;
size?: ModelSizeInput | null;
};
export type ModelSizeInput = {
ne?: number | null;
eq?: number | null;
le?: number | null;
lt?: number | null;
ge?: number | null;
gt?: number | null;
between?: Array<number | null> | null;
};
export type IotTestConnection = {
__typename: "IotTestConnection";
items?: Array<IotTest | null> | null;
nextToken?: string | null;
};
export type CreateIotTestMutation = {
__typename: "IotTest";
iot_test: string;
};
export type UpdateIotTestMutation = {
__typename: "IotTest";
iot_test: string;
};
export type DeleteIotTestMutation = {
__typename: "IotTest";
iot_test: string;
};
export type GetIotTestQuery = {
__typename: "IotTest";
iot_test: string;
};
export type ListIotTestsQuery = {
__typename: "IotTestConnection";
items?: Array<{
__typename: "IotTest";
iot_test: string;
} | null> | null;
nextToken?: string | null;
};
export type OnCreateIotTestSubscription = {
__typename: "IotTest";
iot_test: string;
};
export type OnUpdateIotTestSubscription = {
__typename: "IotTest";
iot_test: string;
};
export type OnDeleteIotTestSubscription = {
__typename: "IotTest";
iot_test: string;
};
@Injectable({
providedIn: "root"
})
export class APIService {
public client: Client;
constructor() {
this.client = generateClient();
}
async CreateIotTest(
input: CreateIotTestInput
): Promise<CreateIotTestMutation> {
const statement = `mutation CreateIotTest($input: CreateIotTestInput!) {
createIotTest(input: $input) {
__typename
iot_test
}
}`;
const gqlAPIServiceArguments: any = {
input
};
const response = (await this.client.graphql({
query: statement,
variables: gqlAPIServiceArguments
})) as any;
return <CreateIotTestMutation>response.data.createIotTest;
}
async UpdateIotTest(
input: UpdateIotTestInput
): Promise<UpdateIotTestMutation> {
const statement = `mutation UpdateIotTest($input: UpdateIotTestInput!) {
updateIotTest(input: $input) {
__typename
iot_test
}
}`;
const gqlAPIServiceArguments: any = {
input
};
const response = (await this.client.graphql({
query: statement,
variables: gqlAPIServiceArguments
})) as any;
return <UpdateIotTestMutation>response.data.updateIotTest;
}
async DeleteIotTest(
input: DeleteIotTestInput
): Promise<DeleteIotTestMutation> {
const statement = `mutation DeleteIotTest($input: DeleteIotTestInput!) {
deleteIotTest(input: $input) {
__typename
iot_test
}
}`;
const gqlAPIServiceArguments: any = {
input
};
const response = (await this.client.graphql({
query: statement,
variables: gqlAPIServiceArguments
})) as any;
return <DeleteIotTestMutation>response.data.deleteIotTest;
}
async GetIotTest(iot_test: string): Promise<GetIotTestQuery> {
const statement = `query GetIotTest($iot_test: String!) {
getIotTest(iot_test: $iot_test) {
__typename
iot_test
}
}`;
const gqlAPIServiceArguments: any = {
iot_test
};
const response = (await this.client.graphql({
query: statement,
variables: gqlAPIServiceArguments
})) as any;
return <GetIotTestQuery>response.data.getIotTest;
}
async ListIotTests(
filter?: TableIotTestFilterInput,
limit?: number,
nextToken?: string
): Promise<ListIotTestsQuery> {
const statement = `query ListIotTests($filter: TableIotTestFilterInput, $limit: Int, $nextToken: String) {
listIotTests(filter: $filter, limit: $limit, nextToken: $nextToken) {
__typename
items {
__typename
iot_test
}
nextToken
}
}`;
const gqlAPIServiceArguments: any = {};
if (filter) {
gqlAPIServiceArguments.filter = filter;
}
if (limit) {
gqlAPIServiceArguments.limit = limit;
}
if (nextToken) {
gqlAPIServiceArguments.nextToken = nextToken;
}
const response = (await this.client.graphql({
query: statement,
variables: gqlAPIServiceArguments
})) as any;
return <ListIotTestsQuery>response.data.listIotTests;
}
OnCreateIotTestListener(
iot_test?: string
): Observable<
GraphQLResult<Pick<__SubscriptionContainer, "onCreateIotTest">>
> {
const statement = `subscription OnCreateIotTest($iot_test: String) {
onCreateIotTest(iot_test: $iot_test) {
__typename
iot_test
}
}`;
const gqlAPIServiceArguments: any = {};
if (iot_test) {
gqlAPIServiceArguments.iot_test = iot_test;
}
return this.client.graphql({
query: statement,
variables: gqlAPIServiceArguments
}) as any;
}
OnUpdateIotTestListener(
iot_test?: string
): Observable<
GraphQLResult<Pick<__SubscriptionContainer, "onUpdateIotTest">>
> {
const statement = `subscription OnUpdateIotTest($iot_test: String) {
onUpdateIotTest(iot_test: $iot_test) {
__typename
iot_test
}
}`;
const gqlAPIServiceArguments: any = {};
if (iot_test) {
gqlAPIServiceArguments.iot_test = iot_test;
}
return this.client.graphql({
query: statement,
variables: gqlAPIServiceArguments
}) as any;
}
OnDeleteIotTestListener(
iot_test?: string
): Observable<
GraphQLResult<Pick<__SubscriptionContainer, "onDeleteIotTest">>
> {
const statement = `subscription OnDeleteIotTest($iot_test: String) {
onDeleteIotTest(iot_test: $iot_test) {
__typename
iot_test
}
}`;
const gqlAPIServiceArguments: any = {};
if (iot_test) {
gqlAPIServiceArguments.iot_test = iot_test;
}
return this.client.graphql({
query: statement,
variables: gqlAPIServiceArguments
}) as any;
}
}
I then created a basic Angular component to interact with this API:
import { Component, OnInit } from '@angular/core';
import { APIService, CreateIotTestInput, DeleteIotTestInput, UpdateIotTestInput } from '../API.service';
import { CommonModule } from '@angular/common';
@Component({
selector: 'app-iot-test',
template: `
<div>
<h1>Iot Test Component</h1>
<button (click)="createIotTest()">Create Iot Test</button>
<button (click)="updateIotTest()">Update Iot Test</button>
<button (click)="deleteIotTest()">Delete Iot Test</button>
<button (click)="getIotTest()">Get Iot Test</button>
<button (click)="listIotTests()">List Iot Tests</button>
</div>
`,
standalone: true,
imports: [CommonModule],
providers: [APIService]
})
export class IotTestComponent implements OnInit {
constructor(private apiService: APIService) { }
ngOnInit(): void {
}
createIotTest(): void {
const input: CreateIotTestInput = {
iot_test: 'New Iot Test'
};
this.apiService.CreateIotTest(input).then((response) => {
console.log(response);
});
}
updateIotTest(): void {
const input: UpdateIotTestInput = {
iot_test: 'Updated Iot Test'
};
this.apiService.UpdateIotTest(input).then((response) => {
console.log(response);
});
}
deleteIotTest(): void {
const input: DeleteIotTestInput = {
iot_test: 'Iot Test to delete'
};
this.apiService.DeleteIotTest(input).then((response) => {
console.log(response);
});
}
getIotTest(): void {
const iot_test = 'Iot Test to get';
this.apiService.GetIotTest(iot_test).then((response) => {
console.log(response);
});
}
listIotTests(): void {
this.apiService.ListIotTests().then((response) => {
console.log(response);
});
}
}
When I try to interact somehow with API service functions, I get validation errors. for example when I click List IoT Tests button I get two errors.
"Validation error of type UnknownType: Unknown type TableIotTestFilterInput"
and
"Validation error of type FieldUndefined: Field 'listIotTests' in type 'Query' is undefined @ 'listIotTests'"
FYI: I am running on localhost currently