Integrating GraphQL into Angular Apps with Apollo Client

Integrating GraphQL into Angular Apps with Apollo Client

Effectively handling data is crucial for creating responsive applications. While traditional REST APIs have been widely used, the emergence ofGraphQLoffers developers a potent alternative.Angular, a popular web application framework, can seamlessly harness the capabilities of GraphQL throughApollo Client.

Overview of Apollo Client

Apollo Client is a state management library designed for JavaScript applications, particularly those leveraging GraphQL APIs. It offers a suite of functionalities including caching, local state management, and reactive data fetching, providing a powerful means to manage application data and state. Developed by the creators of Apollo GraphQL, it streamlines the integration of GraphQL into front-end applications by offering a cohesive interface for querying and managing data. Compatible with major frontend frameworks like React, Angular, and Vue.js, Apollo Client stands as a versatile solution for crafting contemporary web applications.

Benefits of using Apollo Client include:

  • Efficient Data Fetching: Apollo Client simplifies data fetching by providing a powerful and flexible GraphQL client that efficiently fetches data from a server. It optimizes data fetching by fetching only the data required by the client, minimizing unnecessary requests.

  • Declarative Data Management: Apollo Client offers a declarative approach to data management, allowing developers to specify data requirements using GraphQL queries directly within their Angular components. This approach enhances code readability and maintainability.

  • Normalized Cache: Apollo Client maintains a normalized cache that stores fetched data in a normalized form. This cache improves performance by eliminating redundant data and facilitating efficient retrieval and updates.

  • Real-time Data Updates: Apollo Client seamlessly integrates with GraphQL subscriptions, enabling real-time data updates in Angular applications. This feature is useful for building interactive applications that require instant updates based on server-side changes.

  • Client-side State Management: Apollo Client supports client-side state management, allowing developers to manage local application state alongside remote data. This feature enables centralized state management within Angular applications, simplifying data synchronization and improving scalability.

  • Community Support and Ecosystem: Apollo Client benefits from a thriving community and ecosystem, with extensive documentation, tutorials, and community support available. This ecosystem includes tools, plugins, and integrations that enhance the development experience and address common use cases.

Setting up the Development Environment

To start, initiate a new Angular project using any desired file name. To create the project, execute the following command:

ng new <file name>

Then, navigate into the newly generated directory:

cd <file name>

Subsequently, install the apollo-angular dependency:

ng add apollo-angular

Upon installing the apollo-angular dependency, you will be prompted to specify the URL of your GraphQL API. For demonstration purposes, we will utilize a free API available at “https://countries.trevorblades.com/graphql”. You have the option to develop your own GraphQL API utilizing Node.js. Detailed instructions on how to do so can be found in our previous post, where we walk you through the process step by step.

To modify the GraphQL API, access the graphql.provider.ts file and update the following line of code with your preferred API:

const uri = ' insert your preferred API ';

Next, navigate to the app.component.ts file and import the following dependencies:

import { gql, Apollo } from 'apollo-angular';
import { FormsModule } from '@angular/forms';
import { CommonModule } from '@angular/common';

Then, add FormsModule and CommonModule into the import array within the @Component class:

@Component({
  // other metadata
  imports: [RouterOutlet, CommonModule, FormsModule],
})

Integrating GraphQL into Angular Apps

To integrate GraphQL into our Angular application, we'll start by creating a GraphQL service using Apollo Client. Define a GraphQL query to fetch data.

const Get_MyCountries = gql`
  query Query {
    country(code: "NG") {
      name
      native
      capital
      emoji
      currency
    }
  }`

Next, in the src folder of our project, create a sub-folder named model. Within this sub-folder, create a new file named country.ts. In this TypeScript file, we'll define the structure of the data that our application will utilize. Here's an example of how to define the Country interface:

export interface Country {
  name: string;
  native: string;
  capital: string;
  emoji: string;
  currency: string;
}

This structure will help us maintain a clear and consistent data model throughout our Angular application.

Implementing GraphQL queries

We would implement GraphQL queries in our Angular component for fetching data from a GraphQL API endpoint.

Firstly, within the AppComponent class, we implement the OnInit interface to ensure that the necessary initialization steps occur. Also, create a property country of type Country which we earlier created.

export class AppComponent implements OnInit {

  country!: Country;

  ngOnInit(): void {
    // Initialization logic here
  }

}

Within the constructor of the AppComponent class, we initialize an instance of the Apollo class. This instance, named apollo, is a private property of the class and facilitates interaction with the Apollo Client service, which handles GraphQL operations.

export class AppComponent implements OnInit {
  country!: Country;

  constructor(private apollo: Apollo) {}

  ngOnInit(): void {
    // Initialization logic here
  }

}

In the ngOnInit() method, we execute a GraphQL query to the server by utilizing Apollo Client's watchQuery method. This method requires an options object as an argument, where the query property is set to Get_MyCountries, representing the predefined GraphQL query.

export class AppComponent implements OnInit {
  country!: Country;

  constructor(private apollo: Apollo) {}

  ngOnInit(): void {
    this.apollo
      .watchQuery<any>({
        query: Get_MyCountries
      })
      // Subscription logic here
  }

}

Subsequently, we subscribe to the observable returned by watchQuery, which emits changes in data or loading state. The callback function of the subscription receives an object containing data and loading. Within this function, we validate whether loading is false and whether both data and data.country is true. If these conditions are met, we extract country data from data.country and assign it to the country property of the component.

export class AppComponent implements OnInit {
  country!: Country;

  constructor(private apollo: Apollo) {}

  ngOnInit(): void {
    this.apollo
      .watchQuery<any>({
        query: Get_MyCountries
      })
      .valueChanges.subscribe(({ data, loading }) => {
        if (!loading && data && data.country) {
          this.country = {
            name: data.country.name,
            native: data.country.native,
            capital: data.country.capital,
            emoji: data.country.emoji,
            currency: data.country.currency
          };
        }
      });
  }

}

Displaying data using templates

To display the fetched data in the DOM, we'll utilize a Bootstrap table template. First, ensure the Bootstrap CSS is linked in the index.html file by adding the Bootstrap CDN link:

<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">

Then, create a table element in your HTML template and apply Bootstrap styling classes like table and table-hover to enhance its visual appeal. Use the *ngIf directive to conditionally render the table only when there is valid country data available:

<table class="table table-hover" *ngIf="country">

Define the table headers (thead) within the table element. Each table header (th) represents a column in the table. Specify the headers for the country information you want to display, such as name, native name, capital, emoji, and currency:

<thead>
  <tr>
    <th scope="col">Name</th>
    <th scope="col">Native</th>
    <th scope="col">Capital</th>
    <th scope="col">Emoji</th>
    <th scope="col">Currency</th>
  </tr>
</thead>

After defining the table headers, create the table body (tbody) section. Inside the tbody, define a table row (tr) and its corresponding cells (td). Use Angular interpolation ({{ }}) to display the country information fetched from the country object provided by the component:

<tbody>
  <tr>
    <td>{{ country.name }}</td>
    <td>{{ country.native }}</td>
    <td>{{ country.capital }}</td>
    <td>{{ country.emoji }}</td>
    <td>{{ country.currency }}</td>
  </tr>
</tbody>

In each table cell, access the specific property of the country object to display its name, native name, capital, emoji, and currency. Ensure that the country object is properly initialized and passed to the template from the component.

Finally, here's a snapshot of the data fetched from the GraphQL API.

Conclusion

Integrating GraphQL into Angular apps with Apollo Client offers developers a streamlined approach to managing data and state. With features like efficient data fetching, declarative data management, and real-time updates, Apollo Client simplifies working with GraphQL APIs in Angular projects. By leveraging these technologies, developers can build responsive web applications with ease.

Additional Resources

Apollo graphql