xyz-data / graphql-js

A reference implementation of GraphQL for JavaScript
http://graphql.org/graphql-js/
Other
1 stars 0 forks source link

Schemas and Types #3

Open xgqfrms-GitHub opened 6 years ago

xgqfrms-GitHub commented 6 years ago

Schemas and Types

http://graphql.org/learn/schema

On this page, you'll learn all you need to know about the GraphQL type system and how it describes what data can be queried.

Type system


# the GraphQL query language is basically about selecting fields on objects. 

{
    hero {
        name
        appearsIn
    }
}

{
    "data": {
        "hero": {
            "name": "R2-D2",
            "appearsIn": [
                "NEWHOPE",
                "EMPIRE",
                "JEDI"
            ]
        }
    }
}

Type language


# GraphQL services can be written in any language. 

# We'll use the "GraphQL schema language" 
# it's similar to the query language, and allows us to talk about GraphQL schemas in a `language-agnostic` way.

# `与语言无关`
# agnostic 不可知

Object types and fields


type Character {
    name: String!
    appearsIn: [Episode]!
}

# `Character` is a `GraphQL Object Type`, meaning it's a type with some fields. 
# Most of the types in your schema will be object types.

# `name` and `appearsIn` are `fields` on the `Character` type.
# That means that name and appearsIn are the only fields that can appear in any part of a GraphQL query that operates on the Character type.

# `String` is one of the built-in `scalar types`
# these are types that resolve to a single scalar object, and can't have sub-selections in the query. 
# scalar types, 标量类型

# `String!` means that the field is `non-nullable`,
# meaning that the GraphQL service promises to always give you a value when you query this field.
# exclamation mark, 感叹号

Arguments


type Starship {
    id: ID!
    name: String!
    length(unit: LengthUnit = METER): Float
    # defined argument: `unit`
    # default value: `METER`
    # scalar types: `Float`
}

# All arguments are named.
# all arguments in GraphQL are passed by name specifically. 
# In this case, the `length` field has one defined argument, `unit`.

# Arguments can be either required or optional. 
# When an argument is optional, we can define a `default value` - if the unit argument is not passed, it will be set to `METER` by default.

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:

# Every GraphQL service has a `query type` and may or may not have a `mutation type`. 

schema {
    query: Query
    mutation: Mutation
}

# These types are the same as a regular object type, but they are special because they define the entry point of every GraphQL query.

query {
    hero {
        name
    }
    droid(id: "2000") {
        name
    }
}

# That means that the GraphQL service needs to have a Query type with hero and droid fields:

type Query {
    hero(episode: Episode): Character
    droid(id: ID!): Droid
}

# Mutations work in a similar way 
# you define fields on the Mutation type, and those are available as the root mutation fields you can call in your query.

{
    "data": {
        "hero": {
            "name": "R2-D2"
        },
        "droid": {
            "name": "C-3PO"
        }
    }
}

Scalar types

# A GraphQL object type has a name and fields, but at some point those fields have to resolve to some concrete data.
# 一个 GraphQL 对象类型具有名称和字段,但在某些时候,这些字段必须解析为某些具体数据。

{
    hero {
        name
        appearsIn
    }
}

# GraphQL comes with a set of default scalar types out of the box:

# 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: The ID scalar type represents a unique identifier, often used to refetch an object or as the key for a cache. 
# The ID type is serialized in the same way as a String; 
# however, defining it as an ID signifies that it is not intended to be human‐readable.

# In most GraphQL service implementations, there is also a way to specify custom scalar types.
# Then it's up to our implementation to define how that type should be serialized, deserialized, and validated.

`scalar Date`

{
    "data": {
        "hero": {
            "name": "R2-D2",
            "appearsIn": [
                "NEWHOPE",
                "EMPIRE",
                "JEDI"
            ]
        }
    }
}

Enumeration types

Enums, enumeration types are a special kind of scalar that is restricted to a particular set of allowed values.


enum Episode {
    NEWHOPE
    EMPIRE
    JEDI
}

# This means that wherever we use the type Episode in our schema, we expect it to be exactly one of NEWHOPE, EMPIRE, or JEDI.

# in a language like JavaScript with no enum support, these values might be internally mapped to a set of integers.
# 在没有枚举支持的JavaScript语言中,这些值可能在内部映射到一组整数。

Lists and Non-Null


# But when you use the types in other parts of the schema, or in your query variable declarations, 
# you can apply additional `type modifiers` that affect validation of those values.

type Character {
    name: String!
    appearsIn: [Episode]!
}

# we're using a `String type` and marking it as `Non-Null` by adding an exclamation mark, `!` after the type name. 

# The Non-Null type modifier can also be used when defining arguments for a field,

query DroidById($id: ID!) {
    droid(id: $id) {
        name
    }
}

# We can use a `type modifier` to mark a type as a `List`, which indicates that this field will return an `array` of that type.
# In the schema language, this is denoted by wrapping the type in `square brackets`, [ and ]. 

# The Non-Null and List modifiers can be combined. 

myField: [String!]

# This means that the list itself can be null, but it can't have any null members. 

myField: null // valid
myField: [] // valid
myField: ['a', 'b'] // valid
myField: ['a', null, 'b'] // error

# defined a Non-Null List of Strings:

myField: [String]!

# This means that the list itself cannot be null, but it can contain null values:

myField: null // error
myField: [] // valid
myField: ['a', 'b'] // valid
myField: ['a', null, 'b'] // valid

# You can arbitrarily nest any number of Non-Null and List modifiers, according to your needs.
# 可以根据需要随意嵌套任意数量的非空和列表修饰符。

{
    "data": {
        "droid": null
    }
}

{
    "data": {
        "droid": null
    }
}

Interfaces

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


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

# Star Wars trilogy 星球大战三部曲
# This means that any type that implements Character needs to have these exact fields, with these arguments and return types.

type Human implements Character {
    id: ID!
    name: String!
    friends: [Character]
    appearsIn: [Episode]!
    starships: [Starship]
    totalCredits: Int
}

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

query HeroForEpisode($ep: Episode!) {
    hero(episode: $ep) {
        name
        primaryFunction
    }
}

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

{
    "ep": "JEDI"
}

{
    "errors": [
        {
            "message": `
                Cannot query field \"primaryFunction\" on type \"Character\". 
                Did you mean to use an inline fragment on \"Droid\"?
            `,
            "locations": [
                {
                "line": 4,
                "column": 5
                }
            ]
        }
    ]
}

{
    "data": {
        "hero": {
        "name": "R2-D2",
            "primaryFunction": "Astromech"
        }
    }
}

Union types

Union types are very similar to interfaces, but they don't get to specify any common fields between the types


# Note that members of a union type need to be concrete object types;
# you can't create a union type out of interfaces or other unions.

union SearchResult = Human | Droid | Starship

{
    search(text: "an") {
        ... on Human {
            name
            height
        }
        ... on Droid {
            name
            primaryFunction
        }
        ... on Starship {
            name
            length
        }
    }
}

{
    search {
        ... on Human {
            name
            height
        }
        ... on Droid {
            name
            primaryFunction
        }
        ... on Starship {
            name
            length
        }
    }
}

{
    "data": {
        "search": [
            {
                "name": "Han Solo",
                "height": 1.8
            },
            {
                "name": "Leia Organa",
                "height": 1.5
            },
            {
                "name": "TIE Advanced x1",
                "length": 9.2
            }
        ]
    }
}

{
    "data": {
        "search": [
            {
                "name": "Luke Skywalker",
                "height": 1.72
            },// Human
            {
                "name": "Darth Vader",
                "height": 2.02
            },
            {
                "name": "Han Solo",
                "height": 1.8
            },
            {
                "name": "Leia Organa",
                "height": 1.5
            },
            {
                "name": "Wilhuff Tarkin",
                "height": 1.8
            },
            {
                "name": "C-3PO",
                "primaryFunction": "Protocol"
            },// Droid
            {
                "name": "R2-D2",
                "primaryFunction": "Astromech"
            },
            {
                "name": "Millenium Falcon",
                "length": 34.37
            },
            {
                "name": "X-Wing",
                "length": 12.5
            },
            {
                "name": "TIE Advanced x1",
                "length": 9.2
            },// Starship
            {
                "name": "Imperial shuttle",
                "length": 20
            }
        ]
    }
}

Input types

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


input ReviewInput {
    stars: Int!
    commentary: String
}

# This is particularly valuable in the case of `mutations`, where you might want to pass in a whole object to be created.

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

# The fields on an input object type can themselves refer to input object types,
# but you can't mix input and output types in your schema.

# Input object types also can't have arguments on their fields.

{
    "ep": "JEDI",
    "review": {
        "stars": 5,
        "commentary": "This is a great movie!"
    }
}

{
    "data": {
        "createReview": {
            "stars": 5,
            "commentary": "This is a great movie!"
        }
    }
}
xgqfrms-GitHub commented 6 years ago

https://github.com/gildata/graphql-js/issues/1#issuecomment-332059774

https://github.com/gildata/graphql-js/tree/master/Tutorials/

image

image

https://github.com/gildata/graphql-js/tree/master/Tutorials/Demos