graphql-js 是官方实现
REST 把资源网络堪称虚拟状态机, 并且由用户执行的动作都是机器内的状态变化.
GraphQL 与 REST 耦合是较好的过渡性方案
Realy 和 Apollo
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).
支持 查询 (Query), 变更 (Mutation), 订阅 (subscription).
网页版的 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 }
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 } } }
""" comment """ type User { }