Usage
Once you've gotten set up, it's time to start building your app's components. What does building an app with GraphQL look like? What kinds of components does it have? This introductory guide will help you understand what it's like to build with Apollo Elements.
The Concept
In a GraphQL app, you'll use queries and mutations to interact with your application's data graph. GraphQL helps you model your frontend's data in terms of queries.
A query is a self-contained slice of the state of your app's data graph, and a mutation is a self-contained action to affect a slice of your graph. They fit naturally into the data-driven web components development model, since a web component is a self-contained unit of HTML UI with programmer-defined behaviours.
Using Apollo Elements, you'll build query components to fetch and display data from the graph and mutation components to make changes to the graph. You can also publish self-contained GraphQL components for others to use in their apps, for example if multiple teams work on the same large dashboard app.
Many Paths to Success
With Apollo Elements, you can write declarative templates and styles for your component in HTML, or you can leverage your favourite web-components library to write your own custom query, mutation, or subscription component. Apollo Elements coordinates between your UI library of choice (or your declarative HTML template) and the Apollo client. Add your query, template, styles, and custom behaviours to Apollo Elements' components, base classes, or helpers functions.
The tabs below demonstrate multiple ways to write the same query component:
<apollo-query>
<!-- Use a script child like so,
or set the `query` DOM property on the element -->
<script type="application/json">
query Users {
users {
id
name
picture
}
}
</script>
<template>
<h2>Astronauts</h2>
<template type="repeat" repeat="{{ data.users }}">
<astro-naut id="{{ item.id }}" name="{{ item.name }}">
<img src="{{ item.picture }}"
alt="Portrait of {{ item.name }}"/>
</astro-naut>
</template>
</template>
</apollo-query>
import { ControllerHostMixin } from '@apollo-elements/mixins/controller-host-mixin';
import { ApolloQueryController } from '@apollo-elements/core/apollo-query-controller';
const template = document.createElement("template");
template.innerHTML = `
<h2>Astronauts</h2>
<div id="astronauts"></div>
`;
const itemTemplate = document.createElement("template");
itemTemplate.innerHTML = `
<astro-naut name="">
<img />
</astro-naut>
`;
class Astronauts extends ApolloQueryMixin(HTMLElement) {
query = new ApolloQueryController(this, gql`
query Users {
users {
id
name
picture
}
}
`)
constructor() {
super();
this
.attachShadow({ mode: 'open' })
.appendChild(template.content.cloneNode(true));
}
update() {
this.render();
super.update();
}
update() {
const node = this.shadowRoot.getElementById('astronauts');
for (const child of node.children)
child.remove();
for (const { id, name , picture } of this.data?.users ?? []) {
const astronode = itemTemplate.content.cloneNode(true);
astronode.id = id;
astronode.name = name;
const img = astronode.querySelector('img');
img.src = picture;
img.alt = `Portrait of ${name}`;
node.appendChild(astronode);
}
}
}
import { ApolloQueryController } from '@apollo-elements/core/apollo-query-controller';
class Astronauts extends ApolloQuery {
query = new ApolloQueryController(this, gql`
query Users {
users {
id
name
picture
}
}
`);
render() {
return html`
<h2>Astronauts</h2>
${(this.query.data?.users ?? []).map(({ id, name, picture }) => html`
<astro-naut id="${ id }" name="${ name }">
<img src="${ picture }"
alt="Portrait of ${ name }"/>
</astro-naut>
`)}
`;
}
}
import type { TypedDocumentNode } from '@apollo/client/core';
import type { Binding, ViewTemplate } from '@microsoft/fast-element';
import { FASTElement, customElement, html } from '@microsoft/fast-element';
import { ApolloQueryBehavior } from '@apollo-elements/fast';
const getId: Binding<Astronaut> = x => x.id;
const getName: Binding<Astronaut> = x => x.name;
const getPicture: Binding<Astronaut> = x => x.picture;
const getAstronauts: Binding<Astronaut> = x => x.query.data?.users ?? [];
const astronautTemplate: ViewTemplate<Astronaut> = html`
<astro-naut id="${getId}" name="${getName}">
<img src="${getPicture}"
alt="Portrait of ${getName}"/>
</astro-naut>
`;
const template: ViewTemplate<Astronauts> = html`
<h2>Astronauts</h2>
${repeat(getAstronauts, astronautTemplate)}
`;
const AstronautsQuery: TypedDocumentNode<{ users: { id: string; name: string; picture: string } }> = gql`
query Users {
users {
id
name
picture
}
}
`;
@customElement({ name: 'astro-nauts', template })
class Astronauts extends FASTElement {
query = new ApolloQueryBehavior(this, AstronautsQuery);
}
function Astronauts() {
const { data } = useQuery(gql`
query Users {
users {
id
name
picture
}
}
`);
return html`
<h2>Astronauts</h2>
${(data?.users ?? []).map(({ id, name, picture }) => html`
<astro-naut id="${ id }" name="${ name }">
<img src="${ picture }"
alt="Portrait of ${ name }"/>
</astro-naut>
`)}
`;
}
function Astronauts() {
const { data } = useQuery(gql`
query Users {
users {
id
name
picture
}
}
`);
return (
<host shadowDom>
<h2>Astronauts</h2>
{(data?.users ?? []).map(({ id, name, picture }) => (
<astro-naut id={id} name={nam }>
<img src={picture}
alt="Portrait of {name}"/>
</astro-naut>
))}
</host>
);
}
import { query } from '@apollo-elements/hybrids/factories/query';
define('astro-nauts', {
query: query(gql`
query Users {
users {
id
name
picture
}
}
`),
render: host => html`
<h2>Astronauts</h2>
${(host.query.data?.users ?? []).map(({ id, name, picture }) => html`
<astro-naut id="${ id }" name="${ name }">
<img src="${ picture }"
alt="Portrait of ${ name }"/>
</astro-naut>
`)}
`,
});
Apollo Elements doesn't lock you in to one way of working. You can build an app's components piecemeal from several different libraries using multiple different paradigms, and they can all consume each other, communicate with each other, and coexist with one another, and couldn't we use some more of that?
Next Steps
- Learn how to use GraphQL query components to fetch and display your app's data
- Learn how to use GraphQL mutation components to make changes to your data graph
- Learn how to use GraphQL subscription components to add real-time updates to your app