What is GraphQL

GraphQL is a query language for your API, and a server-side runtime for executing queries using a type system you define for your data.

Clients form requests by using the GraphQL query language, and the GraphQL server executes the request and returns the data in a response.

Features

  • The GraphQL query language: basically about selecting fields on objects.
  • A GraphQL service: it is created by defining types and fields on those types, then providing functions for each field on each type.
  • In a GraphQL operation: the client specifies how to structure the data when it is returned by the server. This makes it possible for the client to query only for the data it needs, in the format that it needs it in.
  • GraphQL request structures resemble JSON. However, GraphQL requests don’t use quotes for field names and don’t have colons separating field names and values. Responses are in JSON format.

GraphQL vs REST

We usually compare GraphQL and REST.

REST uses “resources” as its core concept. That means entities are identified by URIs. In contrast, GraphQL’s conceptual model is an entity graph. A GraphQL server operates on a single URL/endpoint, usually /graphql, and all GraphQL requests for a given service should be directed at this endpoint.

In a system like REST, you can only pass a single set of arguments - the query parameters and URL segments in your request. But in GraphQL, every field and nested object can get its own set of arguments, making GraphQL a complete replacement for making multiple API fetches.

GraphQL has three top-level operations:

  1. Query - read-only fetch
  2. Mutation - write, followed by a fetch
  3. Subscription - long-lived connection for receiving data

GraphQL exposes these operations via a schema that defines the capabilities of an API. A schema is comprised of types, which can be root types (query, mutation, or subscription) or user-defined types.

Developers start with a schema to define the capabilities of their GraphQL API, which a client application will communicate with.

Basic example

GraphQL service

A GraphQL service define schema and object types:

type Query {
  me: User
}
type User {
  id: ID
  name: String
}

Along with resolver functions for each field on each type:

function Query_me(request) {
  return request.auth.user
}
function User_name(user) {
  return user.getName()
}

GraphQL Client

After a GraphQL service is running, it can receive GraphQL queries to and execute. For example, the query:

{
  me {
    name
  }
}

Could produce the following JSON result:

{
  "me":{
    "name": "Luke Skywalker"
  }
}

Basic Concepts

  • The Operation Type is either query, mutation, or subscription and describes what type of operation you’re intending to do.
  • The Operation Name is a meaningful and explicit name for your operation.
  • fragments: (just like Functions) GraphQL includes reusable units called fragments. Fragments let you construct sets of fields, and then include them in queries where you need to.
  • Variables: ($variableName: variableType) All declared variables must be either scalars, enums, or input object types.
  • Arguments: (just like arguments in Function()) In a system like REST, you can only pass a single set of arguments - the query parameters and URL segments in your request. In GraphQL, every field and nested object can get its own set of arguments. It let you fetch more specific data.
  • Aliases: They let you rename the result of a field to anything you want.
  • Directives: The core GraphQL specification includes exactly two directives, which must be supported by any spec-compliant GraphQL server implementation:
    • @include(if: Boolean) Only include this field in the result if the argument is true.
    • @skip(if: Boolean) Skip this field if the argument is true.

GraphQL schema language

The GraphQL specification defines a human-readable schema definition language (or SDL) that you use to define your schema and store it as a string.

Every type definition in a GraphQL schema belongs to one of the following categories:

  • Scalar
  • Object
    • This includes the three special root operation types: Query, Mutation, and Subscription.
  • Input
  • Enum
  • Union
  • Interface

Object type

The most basic components of a GraphQL schema are object types, which just represent a kind of object you can fetch from your service, and what fields it has. Like this:

type Book {
  title: String
  author: Author
}

type Author {
  name: String
  books: [Book]
}

The Query and Mutation types

Most types in your schema will just be normal object types, but there are two types that are special within a schema:

schema {
  query: Query
  mutation: Mutation
}

The Query type

The Query type is a special object type that defines all of the top-level entry points for queries that clients execute against your server. Like this:

type Query {
  books: [Book]
  authors: [Author]
}

Scalar types:

They represent the leaves of the query. GraphQL’s default scalar types are:

  • Int: A signed 32‐bit integer
  • Float: A signed double-precision floating-point value
  • String: A UTF‐8 character sequence
  • Boolean: true or false
  • ID (serialized as a String): A unique identifier that’s often used to refetch an object or as the key for a cache. Although it’s serialized as a String, an ID is not intended to be human‐readable.

Interface type:

An Interface is an abstract type that includes a certain set of fields that a type must include to implement the interface. (Like class)

Union types:

Union types are very similar to interfaces, but they don’t get to specify any common fields between the types. union SearchResult = Human | Droid | Starship Wherever we return a SearchResult type in our schema, we might get a Human, a Droid, or a Starship.

Input types:

In the GraphQL schema language, input types look exactly the same as regular object types, but with the keyword input instead of type:

input ReviewInput {
  stars: Int!
  commentary: String
}

Input type is particularly valuable in the case of mutations, where you might want to pass in a whole object to be created. Input object types can’t have arguments on their fields.

Apollo GraphQL

Apollo provides the developer platform and tools to unify your data and services into a supergraph (a single distributed GraphQL API).

Graphql Server Setup

Apollo Server is an open-source, spec-compliant GraphQL server that’s compatible with any GraphQL client. You can easily to setup a GraphQL server for test or production by using Apollo Server.

Here are the steps to create you own Graphql Server:

Setup Apollo Server

Fellowing the doc of Apollo Server, You can easily setup a GraphQL server.

Implement Schema and Resolver for Server

  • You need to write code for Schema and Resolvers.
  • Resolvers need to corresponse to Schema. All the Schema need to have a Resolver to response.
  • Apollo can help you simplize the resolvers. For example, client query books {title}, your resolver can just write this: books: () => db.books,. Apollo can just send title instead all fields.

Setup for Using Query Variable

What you need is a query type schema and responsed resolver. query type schema:

type Query {
  game_by_title(title: String!): Game
}

You resolver:

game_by_title(_, args) {
  return db.games.find((game) => game.title === args.title)
}

Now, you can run QUERY plus Variable JSON to query data from client side. For example:

query GGame($title: String!) {
  game_by_title(title:$title) {
    id
    platform
  }
}

Variable:

{
  "title": "Pokemon Scarlet"
}

You can get the response from Server.

  • You need to define the related data in your schema OBJECT type.
  • you need to implement resolver for that related data as well.
    • You will use parent parameter in your resolver.

Set up Mutation

It is similar to Query.

  • It need define type in schema using Mutation.
  • It need corresponsed resolver.
  • When you add item, you may need input type. Like this:
    input AddGameInput {
      title: String!,
      platform: [String!]!
    }
    

For example add a new game, send command from client:

mutation addAGame($agame: AddGameInput!){
  addGame(game: $agame){
    title
    id
  }
}

variable:

{
  "agame": {
    "title": "new name",
    "platform": ["Switch"]
  }
}

Some concepts from Apollo GraphQL

What is Apollo Client

Apollo Client is a state management library for JavaScript. It enables you to manage both local and remote data with GraphQL. Use it to fetch, cache, and modify application data. And also it can help automatically updating your UI.

Basic idea is: (For example, React lib)

  • provide context ApolloProvider to wrap your whole app, then you can use data everywhere.
  • Apollo Client provide useQuery hook to query data.
import { useQuery, gql } from '@apollo/client';

function DisplayLocations() {
  const { loading, error, data } = useQuery(GET_LOCATIONS);

  if (loading) return <p>Loading...</p>;
  if (error) return <p>Error : {error.message}</p>;

  return data.locations.map(({ id, name, description, photo }) => (
    <div key={id}>
      <h3>{name}</h3>
      <img width="400" height="250" alt="location-reference" src={`${photo}`} />
      <br />
      <b>About this location:</b>
      <p>{description}</p>
      <br />
    </div>
  ));
}

Whenever this component renders, the useQuery hook automatically executes our query and returns a result object containing loading, error, and data properties. When the result of your query comes back, it’s attached to the data property.

What is Apollo Federation?

Apollo Federation lets you declaratively combine multiple GraphQL APIs into a single, federated graph. This federated graph enables clients to interact with multiple APIs through a single request.

A client makes a request to the single entry point of the federated graph called the router. The router intelligently orchestrates and distributes the request across your APIs and returns a unified response. For a client, the request and response cycle of querying the router looks the same as querying any GraphQL server.

What’s in a supergraph?

Every supergraph uses an open architecture called Apollo Federation, which consists of the following parts:

  • The graph router
  • One or more subgraphs
  • Backing data sources (databases, REST APIs, etc.)

What is Apollo GraphOS?

Apollo GraphOS is the platform for building, managing, and scaling a supergraph: a network of your microservices and their data sources—all composed into a unified GraphQL API.

FAQ

How to use fragment

Here’s the declaration of a NameParts fragment that can be used with any Person object:

fragment NameParts on Person {
  firstName
  lastName
}

Every fragment includes a subset of the fields that belong to its associated type. In the above example, the Person type must declare firstName and lastName fields for the NameParts fragment to be valid.

We can now include the NameParts fragment in any number of queries and mutations that refer to Person objects, like so:

query GetPerson {
  people(id: "7") {
    ...NameParts
    avatar(size: LARGE)
  }
}

Based on our NameParts definition, the above query is equivalent to:

query GetPerson {
  people(id: "7") {
    firstName
    lastName
    avatar(size: LARGE)
  }
}

References