An open-source library for server-side GraphQL operation handling
Apollo is set of tools for working with GraphQL
Apollo has both client
and server
libraries
// client = query = request import { ApolloClient, HttpLink } from '@apollo/client'; const client = new ApolloClient({ link: new HttpLink({ uri: 'your client uri goes here', fetchOptions: { ... } }), }); // server const { ApolloServer } = require("apollo-server"); const typeDefs = require("./schema"); const server = new ApolloServer({ // schema goes here, it can be string, DocumentNode, or array of either that will be merged together typeDefs: typeDefs, // resolvers = how and where to fetch the data corresponding to a field dataSources: () => { return ( { objectField: () => { return { "field": "value" } } } ) } }); // schema = gql typed schema system const { gql } = require("apollo-server"); const typeDefs = gql` # Your schema will go here `; module.exports = typeDefs;
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
.
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; }