Logo

dev-resources.site

for different kinds of informations.

GraphQL in Your Ember App with Glimmer Apollo

Published at
12/5/2023
Categories
ember
graphql
apollo
glimmer
Author
eugenioenko
Categories
4 categories in total
ember
open
graphql
open
apollo
open
glimmer
open
Author
11 person written this
eugenioenko
open
GraphQL in Your Ember App with Glimmer Apollo

Introduction:

Ember.js, a robust JavaScript framework for building ambitious web applications, has gained popularity for its convention over configuration approach and developer-friendly features. To enhance data fetching and management in Ember applications, integrating GraphQL is a powerful choice. In this article, we'll explore how to unleash the capabilities of GraphQL in your Ember app using Glimmer Apollo.

1. Starting new Ember Project

We can create a new Ember project by using ember-cli. If you don't have it already installed, its as simple as

yarn global add ember-cli
or 
npm install -g ember-cli
Enter fullscreen mode Exit fullscreen mode

Once you have ember-cli installed, to create a new Ember project:

ember new my-project-name
cd my-project-name
Enter fullscreen mode Exit fullscreen mode

2. Adding Typescript Support (optional)

This step is not strictly necessary but without it, you won't get the benefit of type checking on your queries.
Installing ember-cli-typescript allows to write ember component using typescript instead of javascript.

yarn add --dev ember-cli-typescript
Enter fullscreen mode Exit fullscreen mode

3. Installing Glimmer Apollo and Dependencies

We will be using Glimmer Apollo to integrate the Apollo Client. To install the necessary dependencies:

yarn add -dev glimmer-apollo @apollo/client graphql
Enter fullscreen mode Exit fullscreen mode

Thats it, all the Glimmer Apollo dependencies are installed

4. Configuring Apollo Client

To be able to use Apollo Client, we need to configure it and create an instance of the client first.
Create a script file in your project, in this example we are gonna be using /app/config/apollo.ts

// Import the setClient function from the "glimmer-apollo" package.
import { setClient } from "glimmer-apollo";

// Import necessary Apollo Client modules.
import {
  ApolloClient,
  InMemoryCache,
  createHttpLink,
} from "@apollo/client/core";

// Define a function that sets up and configures the Apollo Client.
export default function setupApolloClient(context: object): void {
  // Create an HTTP link that points to the GraphQL server.
  const httpLink = createHttpLink({
    uri: "https://graphqlzero.almansi.me/api",
  });

  // Create an in-memory cache for Apollo Client to store data.
  const cache = new InMemoryCache();

  // Create an instance of Apollo Client with the configured link and cache.
  const apolloClient = new ApolloClient({
    link: httpLink,
    cache,
  });

  // Set the Apollo Client instance on the provided context object.
  setClient(context, apolloClient);
}
Enter fullscreen mode Exit fullscreen mode

The previous code imports the necessary modules from the "apollo/client/core" package, including the ApolloClient class, InMemoryCache, and createHttpLink function. The setupApolloClient function is then defined, which creates an HTTP link pointing to a GraphQL server (in this case, "https://graphqlzero.almansi.me/api" which is a mock graphql api), an in-memory cache for storing Apollo Client data, and finally, an instance of the Apollo Client with the configured link and cache. The created Apollo Client instance is then set on the provided context object using the setClient function from the "glimmer-apollo" package.

Remember to update the createHttpLink uri parameter to the url of your Graphql api

Finally, to instantiate the previous initialization code, we can use Embers Instance Initializer.

Application instance initializers are run as an application instance is loaded. They provide a way to configure the initial state of your application, as well as to set up dependency injections that are local to the application instance.

To create an Instance Initializer for our Apollo Client configuration you can execute:

ember generate instance-initializer apollo
Enter fullscreen mode Exit fullscreen mode

Or simple create a file /app/instance-initializer/apollo.ts

import setupApolloClient from "../config/apollo";

export default {
  initialize: setupApolloClient,
};
Enter fullscreen mode Exit fullscreen mode

We set the setupApolloClient function exported from previous step so that it is run once the application instance is loaded.

And thats it, Glimmer Apollo is ready to be used!

4. Adding 1st Graphql Query

Lets create our first Graphql query and used in a component. We can do so by creating the following files.

app
└── components
    └── first-query
        ├── index.hbs
        ├── index.ts
        └── resources.ts
Enter fullscreen mode Exit fullscreen mode

4.1 Defining Glimmer Apolllo Query in resources.ts

The api we are using for this tutorial has quit a few queries defined, you can explore the schema here: https://graphqlzero.almansi.me/api

For this tutorial we are gonna be fetching the a user name by his id. We can achieve that with the following query

export function useUserByIdQuery<T extends UseQuery<any, any>>(
  ctx: Object,
  args?: T["args"]
): T["return"] {
  return useQuery(ctx, () => [
    gql`
      query UserById($id: ID!) {
        user(id: $id) {
          id
          name
        }
      }
    `,
    args ? args() : {},
  ]);
}
Enter fullscreen mode Exit fullscreen mode

There are three important parts to this code.

The query section query UserById($id: ID!) { where we define the query we want to execute.

The UseQuery<any, any> defines the type of the arguments the query receives and the type of data the query returns. For now its <any, any> but we will fix it in the step 5.

4.2 Using the Glimmer Apollo Query in our component class

import Component from "@glimmer/component";
import { useUserByIdQuery } from "./resources";

export default class FirstQuery extends Component {
  query = useUserByIdQuery(this, () => ({
    variables: {
      id: 1,
    },
  }));
}
Enter fullscreen mode Exit fullscreen mode

The useUserByIdQuery takes in two arguments.
First is the context for the execution of the query. Usually this will be the instance of the component in which the query is used. Its required so that Glimmer Apollo can cleanup properly the resources after the component is destroyed.

Second argument is a list of arguments to pass to the Apollo Client to modify how the query is executed. More info here

We need to pass the Id of the user we want to fetch. We can do that by passing it as the variables property of the arguments

4.3 Fetching the data in the template

{{#if this.query.loading}}
  loading...
{{else if this.query.error}}
  {{this.query.error}}
{{else if this.query.data}}
  {{this.query.data.user.name}}
{{/if}}
Enter fullscreen mode Exit fullscreen mode

When we access the loading or data properties of the query, Glimmer Apollo will execute the query and fetch the data making it available in the data property. And if there was an error it will set the error property of the query.

Finally, to view this in action, use the <FirstQuery /> component.

One thing to note is that the variables passed to the query are reactive. If the variable is a tracked variable, when its value changes the query will execute again.

import Component from "@glimmer/component";
import { tracked } from "@glimmer/tracking";
import { useUserByIdQuery } from "./resources";

export default class FirstQuery extends Component {
  @tracked userId = 1;

  query = useUserByIdQuery(this, () => ({
    variables: {
      id: this.userId,
    },
  }));
}
Enter fullscreen mode Exit fullscreen mode

If we change the value of this.userId = 2 the query will execute again and fetch the data for user with Id 2.

5. Adding Graphql Code Generator (optional)

GraphQL Code Generator is a plugin-based tool that helps you get the best out of your GraphQL stack.

From back-end to front-end, GraphQL Code Generator automates the generation of:

Typed Queries, Mutations and, Subscriptions for React, Vue, Angular, Next.js, Svelte, Ember whether you are using Apollo Client, URQL or, React Query.
Typed GraphQL resolvers, for any Node.js (GraphQL Yoga, GraphQL Modules, TypeGraphQL or Apollo) or Java GraphQL server.

To add graphql-codegen to our project:

yarn add --dev @graphql-codegen/cli @graphql-codegen/typescript @graphql-codegen/typescript-operations @graphql-codegen/named-operations-object
Enter fullscreen mode Exit fullscreen mode

After the dependency is installed we need to initiate the code generator. This can be done by executing:

Add the following config in the root of the project codegen.yml

overwrite: true
hooks:
  afterAllFileWrite:
    - prettier --write
schema: [
  'https://graphqlzero.almansi.me/api',
]
documents: 'app/**/*.{graphql,ts}'
generates:
  types/graphqlzero-api/index.d.ts::
    plugins:
      - typescript
      - typescript-operations
  app/utils/gql-operations.ts:
    plugins:
      - named-operations-object
    config:
      identifierName: namedOperations
  tests/mocks/schema.graphql:
    plugins:
      - schema-ast
Enter fullscreen mode Exit fullscreen mode

The key properties of this config are

  • schema: the url of the graphql-api schema
  • documents: the list of files that should be scanned for graphql queries
  • plugins: sets the plugins used for the code generation

Now you can generate the typescript types for your queries. And also a list of the queries and mutations by name which comes in handy for mock testing. To do that, execute graphql-codegen by passing the config file:

graphql-codegen --config codegen.yml
Enter fullscreen mode Exit fullscreen mode

You can also make it more accessible by adding this line in the scripts of pacakge.json

 "codegen": "graphql-codegen --config codegen.yml"
Enter fullscreen mode Exit fullscreen mode

After the graphql types are generated, we can now update our query to include the proper types. Lets revisit how the resources.ts file looks like for our FirstQuery component:

import { gql, useQuery } from "glimmer-apollo";
import type { UseQuery } from "glimmer-apollo";
import type { UserByIdQuery, UserByIdQueryVariables } from "graphqlzero-api";

export function useUserByIdQuery<T extends UseQuery<UserByIdQuery, UserByIdQueryVariables>>(
  ctx: Object,
  args?: T["args"]
): T["return"] {
  return useQuery(ctx, () => [
    gql`
      query UserById($id: ID!) {
        user(id: $id) {
          id
          name
        }
      }
    `,
    args ? args() : {},
  ]);
}
Enter fullscreen mode Exit fullscreen mode

The main difference is now we can use the proper type for our UseQuery UseQuery<UserByIdQuery, UserByIdQueryVariables>

Conclusion

By integrating Glimmer Apollo into your Ember application, you can seamlessly incorporate GraphQL for efficient data fetching and management. This powerful combination enhances your development experience, providing flexibility and performance in handling complex data requirements.

Copy of this project is available in this repository

apollo Article's
30 articles in total
Favicon
A Beginner’s Guide to Building GraphQL APIs with Apollo Server
Favicon
Apollo Client in 6 minutes with ReactJS
Favicon
Automatically Generated GraphQL Middleware Service
Favicon
GraphQL Federation with Ballerina and Apollo - Part II
Favicon
GraphQL Federation with Ballerina and Apollo - Part I
Favicon
Cookies Setup in Apollo Studio for NodeJS GraphQL Servers
Favicon
Understanding Apollo Client Cache: How to Manage and Update Nested Data Structures Effectively
Favicon
All you need to know about Apollo-Angular Queries
Favicon
GraphQL Code Generator with TypeScript, React and Apollo Client
Favicon
Apollo GraphQL products for dummies
Favicon
Apollo Federation with Local Subgraphs in a Single Node Process
Favicon
GraphQL in Your Ember App with Glimmer Apollo
Favicon
How to solve the N plus 1 problem in GraphQL with Prisma and Apollo
Favicon
Help! Apollo is changing my graphql query response
Favicon
Handle Multiple Queries & Mutations in React Form using Apollo Client
Favicon
Hasura vs Apollo: Comparing GraphQL Platforms
Favicon
Revolutionize Your Next.js State Management with React Button OnClick and Apollo Set Up
Favicon
Apollo integration with MeteorJS v4.2 release and looking to v5
Favicon
The Ultimate GraphQL and Apollo Server Course with Express and TypeScript
Favicon
Working with the Apollo Client in Faust.js
Favicon
Using Postman and Postman Interceptor to authenticate a session cookie based GraphQL API
Favicon
React.Js, GraphQL and Apollo client
Favicon
How we migrated to Apollo Server 4
Favicon
Take your Next js + GraphQL + TypeScript Setup to the next level
Favicon
Pagination in Headless WordPress with WPGraphQL, Apollo, & Next.js
Favicon
Apollo Server Errors for Clients with TypeScript
Favicon
GraphQL and Apollo Server for Beginners: A Practical Guide
Favicon
Appwrite vs. Hasura vs. Apollo
Favicon
GraphQL no front-end (React e Apollo)
Favicon
How to use apollo client cache for local state management

Featured ones: