I've been struggling for hours in order to get my Angular component work with retrieving data from an Apollo GraphQL server by a simple Query (PingGQLService). I'm using apollo-angular 4.1.0 and @apollo/client 3.0.0, even tried with @graphql-codegen/typescript-apollo-angular
This is my App Module:
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 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 my PingGQLService:
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
}
`;
}
This is my Dummy Component:
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);
}
}
And this is the HTML:
<p>dummy works!</p>
<h1>Account:</h1>
<ul>
<li>{{ pingJson }}</li>
<li>{{ ping }}</li>
</ul>
I don't know what is going wrong with my code, it could be something about CORS, but this is my GraphQL server config:
import "module-alias/register";
import "reflect-metadata";
import express from "express";
import session from "express-session";
import { startServer } from "@/app";
import { HOST, NODE_ENV, PORT } from "@/configs/index";
import { loadConsumers } from "@/mq/consumers";
declare module "express-session" {
interface Session {
token: string | undefined;
}
}
loadConsumers()
.then(() => {
console.log("MQ consumers loaded");
})
.catch((error) => {
console.error("MQ consumers failed to load", error);
});
const app = express();
app.use(
session({
secret: "secret",
resave: false,
saveUninitialized: false,
cookie: { secure: true, sameSite: "none", maxAge: 2 * 60 * 60 * 1000 },
})
);
app.set("trust proxy", 1);
// Setup graphql
startServer()
.then((server) => {
server.applyMiddleware({
app,
path: "/graphql",
cors: {
credentials: true,
origin: [
"https://studio.apollographql.com",
"http://localhost:3000/graphql",
"http://localhost:4200",
"http://localhost:4200/",
"*",
],
},
});
app.listen(PORT, () => {
console.log(
`Server running on ${NODE_ENV} mode at http://${HOST}:${PORT}/graphql`
);
});
})
.catch((err) => {
console.error("Error starting server", err);
});
I expect that the HTML gives me this kind of answer:
{
"data": {
"ping": "pong"
}
}
Or even an error, but nothing displays more than this:
I don't get any new log in my console, so I don't know what is happening behind or even if my headers are being sent.
UPDATE: I've simplified the GraphQLModule and changed the DummyComponent according this example, now it doesn't use the service as external, still don't work. These are the changes:
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);
}
}