http://graphql.org/learn

Queries

Fields can be string or array, or object (than you can make subselection). You can pass arguments to fields (like id: 1). Argument can be Enumeration type.

{
  # queries can have comments
  human(id: 1) {
    name
    height(unit: METER)
  }
}

response is

{
  "data: {
    "hero": {
      "name": "My name",
      "height": 4
    }
  }

If you need several items than you can use aliases

{
  importantHuman: human(id:1) {
    name
  }
}

For each alias you can include same set of credentialsFields with named fragments

  niceHuman: human(id: 2) {
  ...credentialsFields
  }
  importantHuman: human(id:1) {
    ... on Character {
      name
    }
  }
  fragment credentialsFields on Character {
    name
  }

Named fragment credentialsFields is included only on type Character since it is defined on it. For importantHuman we used inline fragment.

Variables

Query can have dynamic params which are interpolated on server. Variables has prefix $ and is followed by type. Type can be (Episode is type): scalar, enum or input object type. If type ends with ! than variable is required (otherwise optional). Variables can have default type.

query HeroNameAndFriends($episode: Episode = 'Default Value')
  hero(episode: $episode) {
    name
    friends {
      name
    }
  }

Additional JSON

{
  "episode": "My Episode"
}

Directives

Dinamically include fields with @include(if: $my_var) or @skip(if: ...). This was we can conditionally add some fields.

query Hero($episode: Episode, $withFriends: Boolean!) {
  hero(episode: $episode) {
    name
    friends @include(if: $withFriends) {
      name
    }
  }
}

Introspection

learn When searching results could be union of types, so to determine which type you can request also __typename meta field which will show name of object type.

{
  search(text: 'an') {
    __typename
    name
    ... on Human {
      name
    }
    ... on Droid {
      name
    }
  }
}

returns

{
  "data": {
    "search": [
      {
        "__typename": "Human",
        "name": "My name"
      },
      {
        "__typename": "Droid"
        "name": "My droid name"
      }
    ]
  }
}

__schema is used to see what types are available:

{
  __schema {
    types {
      name
    }
  }
}
{
  "data": {
    "__schema": {
      "types": [
        {
          "name": "Query"
        },
        {
          "name": "Episode"
        },
        {
          "name": "__Schema"
        }
      }
    }
  }
}

queryType.name will return root, probably Query. For __type we can ask:

__type, __fields

Schemas and types

{
  hero {
    name
    appearsIn
  }
}

Select hero field on root object and select name and appearsIn on hero.

type Character {
  name: String!
  appearsIn: [Episode]!
  length(unit: LengthUnit = METER): Float
}

Character is grapqh object type. name is fiels on Character type. With ! means that it is not nullable, its always string. appearsIn is always array (could be empty). length field has argument unit and its optional (METER is default value).

Scalar types are: Int (signed 32 bit integer), Float,String, Boolean and ID. Enumeration types (Enums) are restricted to a set of allowed values. Use string name, similar to constants.

enum Episode {
  NEWHOPE
  EMPIRE
  JEDI
}

Object type, scalars and enums are only kind of types that you can define. There are two type modifiers that affect validation:

When writing query we need to go down to scalar types (can’t ask for field hero).

Interface is abstract type that includes set of fields that a type must include to implement interface. Beside fields, also return types must match.

interface Character {
  id: ID!
  name: String!
  friends: [Character]
  appearsIn: [Episode]!
}

Example implementation

type Droid implements Character {
  id: ID!
  name: String!
  friends: [Character]
  appearsIn: [Episode]!
  someOtherDroidField: String
}

To ask specific object you need to use Inline fragments Inline fragments check if returned type of hero (hero is type Character) is Droid or Human. For hero you can only ask for fields that exists on Character interface. But for specific Droid fiels you can use inline framents

query HeroForEpisode($ep: Episode!) {
  hero(episode: $ep) {
    name
    ... on Droid {
      primaryFunction
    }
    ... on Human {
      height
    }
  }
}

Union type defines possible types. Note that you can’t create union type out of other union type or interface.

union SearchResult = Human | Droid

Mutations

Input types looks exactly the same as regular object types with keyword input. They are used as arguments in mutations

input ReviewInput {
  stars: Int!
  commentary: String
}
mutation CreateReviewForEpisode($ep: Episode!, $review: ReviewInput!) {
  createReview(episode: $ep, review: $review) {
    stars
    commentary
  }
}

data

{
  "ep": "Episode Jedi",
  "review": {
    "stars": 5,
    "commentary": "My comment"
  }
}

Mutation run in sequence, one by one (query run in parallel). Data fields are without $.

Root fields and resolvers

Root type or Query type represents all possible entry points. Resolver receive three params:

Query: {
  human(obj, arg, context) {
    return context.db.loadHumanById(agrs.id).then(
      userData => new Human(userData)
    }
  }
}
Human: {
  name(obj, args, context) {
    return obj.name
  }
}

Testing

https://youtu.be/QHoddukdqf0?t=1918

Permissions:

live queries subscriptions

We get data with GET request and send sada with POST request with query param. Only problem could be caching since we need different strategy for caching.

https://github.com/chentsulin/awesome-graphql https://www.netguru.co/blog/grapghql-vs-rest https://www.howtographql.com/ https://www.compose.com/articles/use-all-the-databases-part-1/ https://www.youtube.com/watch?v=UBGzsb2UkeY&feature=youtu.be https://blog.codeship.com/how-to-implement-a-graphql-api-in-rails/ http://graphqlme.com/2017/09/16/upload-images-to-s3-in-graphql-using-rails-and-paperclip/