Apollo GraphQL Server is unable to provide data to Angular

I've been facing a challenge for quite some time now trying to make my Angular component communicate with an Apollo GraphQL server using a simple Query (PingGQLService). I'm currently utilizing apollo-angular 4.1.0 and @apollo/client 3.0.0, and have even experimented with @graphql-codegen/typescript-apollo-angular

Here is my App Module setup:

import { HttpClientModule } from '@angular/common/http';
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { GraphQLModule } from './graphql.module';

import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { AppMaterialModule } from './app.material.module';

import { DummyComponent } from './components/dummy/dummy.component';
import { PingGQLService } from './services/ping.service';

@NgModule({
    declarations: [
        AppComponent,
        DummyComponent,
    ],
    imports: [
        BrowserModule,
        AppRoutingModule,
        BrowserAnimationsModule,
        AppMaterialModule,
        GraphQLModule,
        HttpClientModule,
    ],
    providers: [PingGQLService],
    bootstrap: [AppComponent],
})
export class AppModule {}

This is the configuration in my GraphQLModule:

import { HttpClientModule, HttpHeaders } from '@angular/common/http';
import { NgModule } from '@angular/core';
import {
    ApolloClientOptions,
    ApolloLink,
    InMemoryCache,
} from '@apollo/client/core';
import { setContext } from '@apollo/client/link/context';
import { onError } from '@apollo/client/link/error';
import { ApolloModule, APOLLO_OPTIONS } from 'apollo-angular';
import { HttpLink } from 'apollo-angular/http';

import { PingGQLService } from './services/ping.service';

const uri = 'http://localhost:3000'; // <-- add the URL of the GraphQL server here
export function createApollo(httpLink: HttpLink): ApolloClientOptions<any> {
    const http = httpLink.create({ uri, withCredentials: true });

    const contentType = setContext((operation, context) => ({
        headers: new HttpHeaders().set('Content-Type', 'application/json'),
    }));

    const proto = setContext((operation, context) => ({
        headers: new HttpHeaders().set('x-forwarded-proto', 'https'),
    }));

    const errorLink = onError(({ graphQLErrors, networkError }) => {
        if (graphQLErrors)
            graphQLErrors.map(({ message, locations, path }) =>
                console.log(
                    `[GraphQL error]: Message: ${message}, Location: ${locations}, Path: ${path}`
                )
            );
        if (networkError) console.log(`[Network error]: ${networkError}`);
    });

    return {
        link: ApolloLink.from([contentType, proto, errorLink, http]),
        cache: new InMemoryCache(),
    };
}

@NgModule({
    exports: [ApolloModule, HttpClientModule],
    providers: [
        {
            provide: APOLLO_OPTIONS,
            useFactory: createApollo,
            deps: [HttpLink],
        },
        PingGQLService,
    ],
})
export class GraphQLModule {}

This is how my PingGQLService is structured:

import { Injectable } from '@angular/core';
import { gql, Query } from 'apollo-angular';

export interface Response {
    pong: string;
}

@Injectable({
    providedIn: 'root',
})
export class PingGQLService extends Query<Response> {
    override document = gql`
        query Ping {
            ping
        }
    `;
}

In addition, this is my Dummy Component in Action:

import { Component, OnInit } from '@angular/core';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';

import { PingGQLService } from 'src/app/services/ping.service';

@Component({
    selector: 'app-dummy',
    templateUrl: './dummy.component.html',
    styleUrls: ['./dummy.component.css'],
})
export class DummyComponent implements OnInit {
    ping!: Observable<string>;
    pingJson!: string;

    constructor(private pingGQL: PingGQLService) {}

    ngOnInit() {
        this.ping = this.pingGQL.watch().valueChanges.pipe(
            map((result) => {
                console.log(result.data);
                return result.data.pong;
            })
        );
        this.pingJson = JSON.stringify(this.ping);
    }
}

The corresponding HTML content:

<p>dummy works!</p>
<h1>Account:</h1>
<ul>
    <li>{{ pingJson }}</li>
    <li>{{ ping }}</li>
</ul>

Despite having difficulties, I intend to receive a response like this through the HTML output:

{
  "data": {
    "ping": "pong"
  }
}

If an error pops up during execution, then it should be visible.

So far, there are no additional logs appearing on the console, leaving me clueless about where things may be going wrong or if the headers are being transmitted properly.

UPDATE: Modifications made to simplify the GraphQLModule and update the DummyComponent based on this reference, still not yielding desired results. Here's what has changed:

import { HttpClientModule } from '@angular/common/http';
import { NgModule } from '@angular/core';

import { ApolloClientOptions, InMemoryCache } from '@apollo/client/core';
import { ApolloModule, APOLLO_OPTIONS } from 'apollo-angular';
import { HttpLink } from 'apollo-angular/http';

const uri = 'http://localhost:3000/graphql';
export function createApollo(httpLink: HttpLink): ApolloClientOptions<any> {
    const http = httpLink.create({ uri });

    return {
        link: http,
        cache: new InMemoryCache(),
    };
}

@NgModule({
    exports: [ApolloModule, HttpClientModule],
    providers: [
        {
            provide: APOLLO_OPTIONS,
            useFactory: createApollo,
            deps: [HttpLink],
        },
    ],
})
export class GraphQLModule {}

import { Component, OnInit } from '@angular/core';
import { Apollo, gql } from 'apollo-angular';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';

export type Query = {
    ping: string;
};

@Component({
    selector: 'app-dummy',
    templateUrl: './dummy.component.html',
    styleUrls: ['./dummy.component.css'],
})
export class DummyComponent implements OnInit {
    ping!: Observable<string>;
    pingJson!: string;

    constructor(private apollo: Apollo) {}

    ngOnInit() {
        this.ping = this.apollo
            .watchQuery<Query>({
                query: gql`
                    query Ping {
                        ping
                    }
                `,
            })
            .valueChanges.pipe(map((result) => result.data.ping));
        this.pingJson = JSON.stringify(this.ping);
    }
}

Answer №1

Surprisingly, the key to my problem was utilizing {{ ping | async }} in the HTML template.

Prior to this, I had no idea about the function of the async pipe in Angular, which caused me a significant amount of stress for around 20 hours.

In addition, thanks to @puelo's input, I was able to streamline my GraphQLModule and it now functions perfectly.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Determining the generic type argument of a class can be unsuccessful due to the specific properties within that class

Why is it that Typescript sometimes fails to infer types in seemingly simple cases? I am trying to understand the behavior behind this. When Typescript's Type Inference Goes Wrong Consider the scenario where we have the following class declarations: ...

Error: Unable to install Angular on WSL due to permission denied for Node

Struggling to set up angular on WSL2, with node version 17.3.1 and npm version 8.3.0 already installed. Received an error when trying the command npm install -g @angular/cli: npm ERR! code 127 npm ERR! path /root/.nvm/versions/node/v17.3.1/lib/node_module ...

Creating a sticky header for a MatTable in Angular with horizontal scrolling

Having an issue with merging Sticky Column and horizontal scrolling. Check out this example (it's in Angular 8 but I'm using Angular 10). Link to Example The base example has sticky headers, so when you scroll the entire page, the headers stay ...

Design buttons that are generated dynamically to match the style

I have a challenge in styling dynamically generated buttons. I've developed a component responsible for generating these dynamic buttons. const TIMER_PRESETS: Record<string, number> = { FIFTHTEENSEC: 15, THIRTYSEC: 30, FORTYFIVESEC: 45, ...

Troubleshooting issue: Unable to successfully update dynamically loaded routes in real-time

I have been attempting to make changes to routes in a lazy-loaded feature module, but I have not been successful. I have tried various methods, including using router.reset(newRoutes), however, none of them have been effective. (Working with Angular 9) exp ...

Instructions for displaying emotes and UTF-8 characters in a Flutter/Java app

In my efforts to display text in Flutter, I am facing the challenge of ensuring that the text is encoded in UTF-8 and can also show emojis. Unfortunately, I have not been successful in achieving both simultaneously. When attempting to decode an input with ...

No indication of component statuses in the augury feature

Augury is a useful Chrome extension for debugging Angular applications. However, I have encountered an issue where it is not displaying any states currently. My setup includes Angular version 5.1.0 and Augury version 1.16.0. ...

What impact does nesting components have on performance and rendering capabilities?

Although this question may appear simple on the surface, it delves into a deeper understanding of the fundamentals of react. This scenario arose during a project discussion with some coworkers: Let's consider a straightforward situation (as illustrat ...

Using TypeScript to Load JSON Data from a Folder

I'm a newcomer to TypeScript and encountering an issue. My task involves dynamically loading objects from a directory that houses multiple JSON files. The file names are generated through an export bash script populating the resource directory. I wan ...

Incorporating a filtering search bar in Ionic React to efficiently sort pre-existing lists based on their titles

Struggling to implement a search bar in my Ionic application has been quite challenging. I've searched for examples and tutorials, but most of them are based on Angular with Ionic. The React example in the Ionic docs didn't provide much help eith ...

Angular - Enhancing the page with valuable information

Recently, I've been developing an Angular application that is designed to function as a digital magazine. This app will feature articles, news, reviews, and more. Along with this functionality, I am looking to include an admin panel where I can easily ...

How can I implement a redirect back to the previous query page post-authentication in Next.js 13?

To enhance security, whenever a user tries to access a protected route, I plan to automatically redirect them to the login page. Once they successfully log in, they will be redirected back to the original protected route they were trying to access. When w ...

How can I showcase array elements using checkboxes in an Ionic framework?

Having a simple issue where I am fetching data from firebase into an array list and need to display it with checkboxes. Can you assist me in this? The 'tasks' array fetched from firebase is available, just looking to show it within checkboxes. Th ...

Is it possible to derive a TypeScript interface from a Mongoose schema without including the 'Document' type?

Using ts-mongoose allows me to define interfaces and schemas for my data in one place. I then export them as a mongoose schema along with the actual interface. The challenge I'm facing is finding a simple way to extract that interface without includi ...

Troubleshooting: Authentication guard not functioning properly in Angular 2 due to HTTP request

As I work on implementing a guard for certain routes in my application, I face an issue. To grant access to the route, my intention is to send an HTTP request to my express backend API and check if the user's session exists. I have explored various e ...

What is the best way to transform the data stored in Observable<any> into a string using typescript?

Hey there, I'm just starting out with Angular and TypeScript. I want to get the value of an Observable as a string. How can this be achieved? The BmxComponent file export class BmxComponent { asyncString = this.httpService.getDataBmx(); curr ...

Identifying the various types in Typescript

In the process of developing a solution for Excel involving data from an Office API, I encountered the challenge of distinguishing between different types that a function can return. Specifically, the data retrieved as a string may belong to either a "Cell ...

How come the variable `T` has been assigned two distinct types?

Consider the following code snippet: function test<T extends unknown[]>(source: [...T], b: T) { return b; } const arg = [1, 'hello', { a: 1 }] const res = test(arg, []) const res1 = test([1, 'hello', { a: 1 }], []) The variabl ...

You can't access the values from one subscribe in Angular 2 within another subscribe (observable) block

Is there a way to properly handle the values from the subscribe method? I am facing an issue where I want to use this.internships in another subscribe method but it keeps returning undefined. Your assistance is greatly appreciated! Code: ngOnInit(): voi ...

Retrieve a specific element from an array list

Hey everyone, I'm facing a problem in my application where I need to extract a specific value from my array and display it in a table for users to see. Check out the code snippet below: Here's my mock data: { "Data": "2020-0 ...