aws / aws/aws-appsync-community
How can I resolve the issue of being unable to utilize the codegen auto-generated AppSync API code in my Amplify Angular application?
- Dominant language
- HTML
- Stars
- 507
- Forks
- 37
- PR merge metrics
- No merged PRs in 30d
Description
### 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 | 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 | null;
};
export type IotTestConnection = {
__typename: "IotTestConnection";
items?: Array | 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 {
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 response.data.createIotTest;
}
async UpdateIotTest(
input: UpdateIotTestInput
): Promise {
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 response.data.updateIotTest;
}
async DeleteIotTest(
input: DeleteIotTestInput
): Promise {
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 response.data.deleteIotTest;
}
async GetIotTest(iot_test: string): Promise {
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 response.data.getIotTest;
}
async ListIotTests(
filter?: TableIotTestFilterInput,
limit?: number,
nextToken?: string
): Promise {
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 response.data.listIotTests;
}
OnCreateIotTestListener(
iot_test?: string
): Observable<
GraphQLResult>
> {
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>
> {
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>
> {
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: `
Iot Test Component
Create Iot Test
Update Iot Test
Delete Iot Test
Get Iot Test
List Iot Tests
`,
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
Contributor guide
Research direction
Start with app.config.ts and the generated API.service file, then inspect the ListIotTests entry point used by the Angular component. Compare the generated operations with the deployed AppSync API schema and reproduce the validation errors from the List IoT Tests button. Done means the generated service and deployed schema agree and the operation can be invoked without those validation errors.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- angular, aws, graphql, typescript
- Domain
- api, backend, frontend
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Needs clarification
- Newbie friendliness
- 35/100