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/