Learning-GraphQL.Reading-Notes.md

Chapter 1, 欢迎来到 GraphQL 的世界

GraphQL 是什么

GraphQL 规范

graphql-js 是官方实现

GraphQL 的设计原则

GraphQL 的起源

数据传输的历史

表述性状态传递

REST 把资源网络堪称虚拟状态机, 并且由用户执行的动作都是机器内的状态变化.

REST 的缺点

过量获取

获取不足

管理 REST 接口

GraphQL 与 REST 耦合是较好的过渡性方案

现实世界中的 GraphQL

GraphQL 客户端库

Realy 和 Apollo

Chapter 2, 图论

图论相关词汇

G = (V ,E). G 代表图形, V代表一组顶点 (Vertice) 或节点 (Node). 例如 V = {1,2,3,4}.

E 代表一组边 (Edge). 例如 E = {{1,2},{1,3},{1,4},{2,4},{3,4}}. 这是无向图 (undirected graph). 如果用圆括号包裹, 则为有向图, 如 E = ({1,2},{1,3},{1,4},{2,4},{3,4}).

图论的历史

柯尼斯堡七桥问题

节点的度数 (degree) 等于连接该节点的边的数量.

我们把每天便只能访问一次的图称为欧拉路径 (Eulerian Path).

树就是图

现实世界中的图形结构

Chapter 3, GraphQL 查询语言

支持 查询 (Query), 变更 (Mutation), 订阅 (subscription).

GraphQL API 工具

GraphiQL

GraphQL Playground

公共 GraphQL API

GraphQL 查询字段

网页版的 playground 虽然一个请求可以写两个 query, 但是只会返回一个结果, 想要全部返回需要写到一个 query 里面.

Query 是根类型 (Root Type)

编写查询时, 把需要的条件字段用大括号括起来, 这些快被称为选择集 (Selection Set), 选择集可以嵌套.

边和连接

查询字段可以是标量类型对象类型. GraphQL 有 5 种标量类型: 整数 (int), 浮点数 (float), 字符串 (string), 布尔值 (bool), 唯一标识符 (ID). ID 虽然返回也是 JSON 字符串, 但会确保返回是唯一的.

片段

片段 (fragment) 可以在多个操作中重用选择集.

# fragment
fragment liftInfo on List {
    name
    status
    capacity
    night
    elevationGain
}

# query
query {
    Lift(id:"jazz-cat") {
        ...liftInfo
        trailAccess {
            name
            difficulty
        }
    }
    Trail(id:"river-run"){
        name
        difficulty
        accessedByLifts {
            ...liftInfo
        }
    }
}

并且 fragment 可以进行嵌套.

query {
    List(id: "jazz-cat") {
        ...liftInfo
        trailAccess {
            ...trailInfo
        }
    }
    Trail(id: "river-run") {
        ...trailInfo
        groomed
        trees
        night
    }
}

fragment trailInfo on Trail {
    name
    difficulty
    accessedByLifts {
        ...liftInfo
    }
}

fragment liftInfo on Lift {
    name
    status
    capacity
    night
    elevationGain
}

联合类型

字段返回多种类型:

query schedule {
    agenda {
        ...on Workout {
            name
            reps
        }
        ...on StudyGroup {
            name 
            subject
            students
        }
    }
}

# returns :

{
    "data": {
        "agenda": [
            {
                "name": "Comp Sci",
                "subject": "CS",
                "students": 12
            },
            {
                "name": "Cardio",
                "reps": 100
            },
            ...
        ]
    }
}

接口

?

变更

新增数据:

mutation createSong {
    addSong(title:"No Scrubs", numberOne: true, performanceName: "TLC") {
        id
        title
        numberOne
    }
}

# returns

{
    "data": {
        "addSong":{
            "id": "5cac5283",
            "title": "No Scrubs",
            "numberOne": true
        }
    }
}

修改数据:

mutation closeLift {
    setLiftStatus(id: "jazz-cat", status: CLOSED) {
        name
        status
    }
}

使用查询变量

将表达式中插入变量:

mutation createSong($title:String!, $numberOne:Int, $by:String!) {
    addSong(title:$title, numberOne:$numberOne, performerName:$by) {
        id
        title
        numberOne
    }
}

# var ref by json

{
    "title": "No Scrubs",
    "numberOne": true,
    "by": "TLC"
}

订阅

subscription {
    liftStatusChange {
        name
        capacity
        status
    }
}

自检

自检 (inrospection)

query {
    __schema {
        types {
            name
            description
        }
    }
}


__schema 用来查询类型, __type用来查询特定类型的详细信息.

抽象语法树

e.g.

query jazzCarStatus {
    Lift(id: "jazz-cat") {
        name
        night
        elevationGain
        trailAccess {
            name
            difficulty
        }
    } 
}

mutation vloseLift($lift: ID!) {
    setLiftStatus(id: $lift, status: CLOSED) {
        ...liftStatus
    }
}

fragment liftStatus on Lift {
    name
    status
}

Chapter 4, 设计 Schema

定义类型

类型

type Photo {
    id: ID!
    name: String!
    url: String!
    description: String
}


感叹号 (!) 表示是感叹号前面的是非空字段.

标量类型

自定义标量类型 DateTime:

scalar DateTime

type Photo {
    id: ID!
    name: String!
    url: String!
    description: String
    created: DateTime!
}

枚举

enum PhotoCategory {
    SELFIE
    PORTAIT
    ACTION
    LANDSCAPE
    GRAPHIC
}

type Photo {
    id: ID!
    name: String!
    category: PhotoCategory!
}

连接和列表

一对一连接

type User {
    githubLogin: ID!
    name: String
    avatar: String
}

type Photo {
    id: ID!
    name: String!
    url: String!
    description: String
    created: DateTime!
    category: PhotoCategory!
    postedBy: User!
}



一对多连接

type User {
    githubLogin: ID!
    name: String
    avatar: String
    postedPhotos: [Photo!]!
}

type Query {
    totalPhotos: Int!
    allPhotos: [Photo!]!
    totalUsers: Int!
    allUsers: [User!]!
}

schema {
    query: Query
}


# query

query {
    totalPhotos
    allPhotos {
        name
        url
    }

}

多对多连接

type User{
    ...
    inPhotots: [Photot!]!
}

type User{
    ...
    taggedPhotots: [Photot!]!
}

直通类型

不同类型的列表

联合类型

union AgendaItem = StudyGroup | Workout

type StudyGroup {
    name: String!
    subject: String
    students: [User!]!
}

type Workout {
    name: String!
    reps: Int!
}

type Query {
    agenda: [AgendaItem!]!
}

union 关键字和竖线 (|) 可以用于声明联合类型.

接口

query schedule {
    agenda {
        name
        start
        end
        ...on Workout {
            reps
        }
    }
}

# schema

scalar DateTime

interface AgendaItem {
    name: String!
    start: DateTime!
    end: DateTime!
}

type StudyGroup implements AgendaItem {
    name: String!
    start: DateTime!
    end: DateTime!
    participants: [User!]!
    topic: String!
}

type Workout implements AgendaItem {
    name: String!
    start: DateTime!
    end: DateTime!
    reps: Int!
}

type Query {
    agenda: [AgendaItem!]!
}


参数

type Query {
    ...
    User(githubLogin: ID!): User!
    Photo(id: ID!): Photo!
}

# query call

query {
    User(githubLogin: "MoonTahoe") {
        name
        avatar
    }
}

query {
    Photo(id:"1235234") {
        name
        description
        url
    }
}



筛选数据

# schema
type Query {
    ...
    allPhotos(category: PhotoCategory): [Photo!]!
}

# query
query {
    allPhoto(category: "SELFIE") {
        name
        description
        url
    }
}

数据分页

type Qeury {
    ...
    allUsers(first: Int=50 start: Int=0): [User!]!
    allPhotos(first: Int=25 start: Int=0): [Photo!]!
}

# query

query {
    allUsers(first: 10, start:90) {
        name
        avatar
    }
}

排序

enum SortDirection {
    ASCENDING
    DESCENDING
}

enum SortablePhotoField {
    name
    description
    category
    created
}

Query {
    allPhotos(
        sort: SortDirection = DESCENDING
        sortBy: SortablePhotoField = created
    ): [Photo!]!
}


# query

query {
    allPhotos(sortBy: name)
}

# query 2

type User {
    postedPhotos(
        first: Int = 25
        start: Int = 0
        sort: SortDirection = DESCENDING
        sortBy: SortablePhotoField = created
        category: PhotoCategory
    ): [Photo!]
}

变更

type Mutation {
    postPhoto(
        name: String!
        description: String
        category: PhotoCategory = PORTRAIT
    ):Photo!
}

schema {
    query: Query
    mutation: Mutation
}


# create

mutation {
    postPhoto(name: "Sending the palisades") {
        id
        url
        created
        postedBy {
            name
        }
    }
}

输入类型

input PostPhotoInput {
    name: String!
    description: String
    category: PhotoCategory = PORTRAIT
}

type Mutation {
    postPhoto(input: PostPhotoInput!): Photo!
}


# create

mutation newPhoto($input: PostPhotoInput!) {
    postPhoto(input: $input){
        id
        url
        created
    }
}

{
    "input": {
        "name": "Hanging",
        "description": "sunny ....",
        "category": "LANDSCAPE"

    }
}

输入类型重新组织和重用.

# schema
input PhotoFilter {
    category: PhotoCategory
    createdBetween: CateRange
    taggedUsers: [ID!]
    searchText: String
}

input DateRange {
    start: DateTime!
    end: DateTime!
}

input DataPage {
    first: Int = 25
    start: Int = 0
}

input DataSort {
    sort: SortDirection = DESCENDING
    sortBy: SortablePhotoField = created
}

type User {
    ...
    postedPhotos(filter:PhotoFilter paging:DataPage sorting: DataSort):[Photo!]!
    inPhotos(filter:PhotoFilter paging:DataPage sorting: DataSort):[Photo!]!
}

type Photo {
    ...
    taggedUsers(sorting:Datasort):[User!]!
}

type Query {
    ...
    allUser(paging: DataPage sorting: DataSort):[User!]!
    allPhotos(filter:PhotoFilter paging:DataPage sorting: DataSort):[Photo!]!
}

# query

query getPhotos($filter:PhotoFilter $page:DataPage $sort:DataSort) {
    allPhotos(filter:$filter paging:$page sorting:$sort){
        id
        name
        url
    }
}

{
    "filter": {
        "category": "ACTION",
        "taggedUsers": ["MoonTahoe", "EvePorcello"],
        "createdBetween": {
            "start": "2018-11-06"
            "end": "2018-05-31"
        }
    },
    "page":{
        "first": 100
    }
}

返回类型

type AuthPayload {
    user: User!
    token: String!
}

type Mutation {
    ...
    githunAuth(code: String!): AuthPayload!
}



订阅类型

type Subscription {
    newPhoto: Photo!
    newUser: User!
}

schema {
    query: Query
    mutation: Mutation
    subscription: Subscription
}

# sub

type Subscription{
    newPhoto(category: PhotoCategory): Photo!
    newUser: User!
}

subscription {
    newPhoto(category: "ACTION"){
        id
        name
        url
        postedBy {
            name
        }
    }
}

schema 文档

"""
comment
"""
type User {

}

Chapter 5, 创建一个 GraphQL API

项目设置