In case you are just tuning in, in this series, we have been taking a close look at GraphQL through the lens of the Apollo toolchain. Part 1 of the series explains some core concepts of GraphQL and introduces Apollo as a GraphQL solution. In Part 2, we took a closer look at building a GraphQL server with Apollo tools. Finally, in this post, we will take a look at the Apollo Client libraries and implement an example client to integrate with the example server from my previous post.
What is Apollo Client?
Apollo has several client implementations available. The core JavaScript library is a good place to start on the JavaScript side.
Apollo also has React and Angular integration packages for the web. In addition, it has an iOS implementation written in Swift! More non-JavaScript platforms (e.g. Java) are currently under development, which is very exciting.
Essentially, the Apollo Client toolchains enable you to integrate with any GraphQL server. They are not opinionated about how to construct your server schemas, and they are extremely flexible. The client libraries implement client-side query caching, query merging and batching, subscriptions, and optimistic UI. In this post, we will take a closer look at the React package in particular.
Configuring the Client
To get started using the library (after installing from npm), we need to set up an ApolloClient
and ApolloProvider
instance. ApolloClient
is the core API for any Apollo Client integration. This is where you configure the network interface, the client side cache, and some global query behaviors.
ApolloProvider
is a React component that wires the ApolloClient
instance into your React component hierarchy. A pretty standard ApolloClient
initialization is shown below. This creates an ApolloClient
instance and specifies a network interface pointing to our GraphQL server’s endpoint (the same one we defined in Part 2). Then it shows how to wire the ApolloClient
instance into the root React tree.
import { ApolloClient, createNetworkInterface } from 'react-apollo';
const client = new ApolloClient({
networkInterface: createNetworkInterface({ uri: 'http://localhost:3000/api/graphql' }),
});
ReactDOM.render(
<ApolloProvider client={client}>
<MyApplication />
</ApolloProvider>,
document.getElementById('root')
)
Querying our Data
Now we are getting to the fun part! Building queries and mutations in Apollo is pretty simple. If you are using the core JavaScript implementation, there are query
and mutate
methods on the ApolloClient
instance, which take a whole variety of parameters.
The most important argument that must be specified in any query or mutation call is the query/mutation string. An example query implementation for the personWithName
query can be found below-this is the same query that we executed in GraphQL at the end of Part 2. The query
and mutate
methods return Promises, so this should be a familiar interface for integrating into your application. Additionally, the query syntax is same GraphQL standard that we are used to, so any query that you can input into the GraphiQL explorer can be used as a query in your Apollo Client.
client.query({
query: gql`
query($name: String!) {
personWithName(name: $name) {
gender,
name,
age
}
}
`,
variables: {
name: 'George',
}
});
As I mentioned earlier, the above example demonstrates the core query
API for ApolloClient
. However, with the React integration package, we have a much nicer API at our disposal. In react-apollo
, queries and mutations are implemented with the graphql
Higher Order Component. This HOC is a very useful utility for React integration because it:
- Takes care of synchronizing the fetching of data with rendering of the presentational component.
- Allows the creation of a declarative query that is bound directly to your props.
- Enables a strong decoupling of presentational components and Apollo.
- Provides hooks for customizing query inputs and child props (after data is received by Apollo).
Let’s take a look at how to build the same personWithName
query with the graphql
HOC. The example below continues the example from the ApolloClient
configuration section above. We define the MyApplication
component and a Greeter
component, which just renders some details about the person which was retrieved by the query.
import { graphql } from 'react-apollo';
import gql from 'graphql-tag';
const Greeter = ({ person }) => <div>Hello {person.name} ({person.age} {person.gender})!</div>;
Greeter.propTypes = {
// comes from MyApplication
desiredName: React.PropTypes.string.isRequired,
// comes from Apollo
person: React.PropTypes.object,
};
Greeter.defaultProps = {
person: {}
};
const PERSON_WITH_NAME_QUERY = gql`
query($name: String!) {
personWithName(name: $name) {
gender,
name,
age
}
}
`;
const GreeterWithData = graphql(PERSON_WITH_NAME_QUERY, {
options: ({ desiredName }) => ({ variables: { name: desiredName } }),
props: ({ data: { personWithName } }) => ({
person: personWithName
}),
})(Greeter);
First, notice the PERSON_WITH_NAME_QUERY
query, which should look identical to the query above. Next, we define the graphql
HOC, passing in the query document and also the options
and props
functions. These two functions are hooks into the Apollo lifecycle that let you customize the query options and the props sent into the child component (i.e. Greeter
, in this case). Each of these functions will be called by Apollo and pass in ownProps
-which is just an object containing all props that were passed into it.
For the options
function, we only care about the desiredName
prop, which is passed in by MyApplication
. Using this prop value, we set the name
variable in the query. If this prop should ever change (for example if the MyApplication
UI had a way for a user to enter in the desired name), then this options
function would cause Apollo to refetch the data when that prop value changed. Pretty cool!
The props
function receives the data
prop from Apollo, which contains the query results along with a loading
status (and a few more things as well). This props
function lets us specify exactly how we want the child component to receive its props. So, in this case, all I want to do is change the personWithName
object name to person
, to allow for a better separation of my presentational component and GraphQL schema. This is obviously a very simple example, but I think it should be enough to see how powerful a mechanism like this is!
The Finished Product
Now, let’s see the result of our query from a browser! The image below shows the result of the query and the Greeter
component. On the left side, you can see George is being greeted with some information about himself. On the right side, you can see the network request/response from the server that was triggered by the graphql
HOC.
Conclusion
This series has been a lot of fun for me to write. There are a lot of awesome features that we didn’t even get a chance to talk about, but I hope this series gave you a good introduction to GraphQL and Apollo. My team has been really happy with Apollo so far, and I am excited to see where the community will go with these tools-I believe this is just the tip of the iceberg for GraphQL!