http://graphql.org/learn
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.
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"
}
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
}
}
}
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:
kind returns __TypeKind enum: OBJECT, INTERFACE, SCALAR, NOT_NULL, LISTfields returns list or fields, if you have NOT_NULL and LIST you can use
ofType to get into exact type__type, __fields
{
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:
! (non null value) can be used also in query[]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
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 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
}
}
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/