Apollo is set of tools for working with GraphQL.
Apollo has both client
and server
libraries.
// client setup import { ApolloClient, HttpLink } from '@apollo/client'; const client = new ApolloClient({ link: new HttpLink({ uri: 'your client uri goes here', fetchOptions: { ... } }), }); // client request using `useQuery` import { useQuery } from "@apollo/client"; const { loading, error, data } = useQuery(QUERY_STRING); if(!loading && !error) { // do something with data console.log(data.field_name); } // schema = gql typed schema system const { gql } = require("apollo-server"); const typeDefs = gql` # Your schema will go here `; module.exports = typeDefs; // server setup const { ApolloServer } = require("apollo-server"); const typeDefs = require("./schema"); const server = new ApolloServer({ // schema goes here typeDefs: typeDefs, // it can be string, DocumentNode, or array of either // definitions will be merged together // resolvers // defines how and where to fetch the data corresponding to a field dataSources: () => { return ( { objectField: () => { return { "field": "value" } } } ) } });
useQuery
import { gql, useQuery } from '@apollo/client'; const GET_DATA = gql` query GetData { data { id name } } `;
Queries are parsed, validated and executed.
A query is first parsed into an abstract syntax tree (or AST).
The AST is validated against the schema. Checks for correct query syntax and if the fields exist.
The runtime walks through the AST, starting from the root of the tree, invokes resolvers
, collects up results, and emits JSON
.
After being validated, a GraphQL query is executed by a GraphQL server which returns a result that mirrors the shape of the requested query, typically as JSON.
GraphQL cannot execute a query without a type system.
At the top level of every GraphQL server is a type
that represents all the possible entry points into the GraphQL API, it’s often called the Root type
or the Query type
.
# root query type Query { # root field person(id: ID!): Person } # root mutation type Mutation { # ... }
The tree is executed breadth-first
, meaning user
must be resolved before its children name
and email
are executed.
Root Query
fields, like user
and album
, are executed in parallel but in no particular order.
If the user
resolver is asynchronous, the user
branch delays until its resolved. Once all leaf nodes, name
, email
, title
, are resolved, execution is complete.
Schema
to a Resolver
Apollo maps the schema to a resolver by matching based on field names.
Apollo also uses type matching.
types
by checking for an object in the resolvers structure that corresponds to each type name (Query, User, etc.).type Query { user(id: ID!): User } type User { id: ID! name: String email: String }
const resolvers = { Query: { user: (parent, args, context) => { /* resolve user by ID */ }, }, User: { name: (parent) => parent.name, email: (parent) => parent.email, }, };
When a field does not have a specified resolver to match, a default resolver
will look in root
to find a property with the same name as the field.
Event: { // will look to resolve identical name in root title: (root, args, context, info) => root.title; }