Toggle navigation
首页
技术
骑行
羽毛球
资讯
联络我
登录
graphql学习笔记
2021-02-10
Web Tool
## GraphQL核心概念 https://segmentfault.com/a/1190000014131950 ## mutation # 定义 ## 一种用于 API 的查询语言 GraphQL 既是一种用于 API 的查询语言也是一个满足你数据查询的运行时。 GraphQL 对你的 API 中的数据提供了一套易于理解的完整描述,使得客户端能够准确地获得它需要的数据,而且没有任何冗余,也让 API 更容易地随着时间推移而演进,还能用于构建强大的开发者工具。 * [英文](https://graphql.org) * [中文](https://graphql.cn) # 入门 ## 查询和变更 ### 字段(Fields) ### 参数(Arguments) ### 别名(Aliases) ### 片段(Fragments) ### 操作名称(Operation Name) ### 变量(Variables) ### 指令(Directives) ### 变更(Mutations) mutation定义的类型用input修饰,如 ```graphql input AccountInput { id: ID Age: Int Name: String } type mutation { updateAccount(id: ID!, input: AccountInput): Account } ``` 注:graphql要求至少要有一个query,否则不会列出mutation方法 ### 内联片段(Inline Fragments) ## Schema 和类型 ### 类型系统(Type System) 因为一个 GraphQL 查询的结构和结果非常相似,因此即便不知道服务器的情况,你也能预测查询会返回什么结果。但是一个关于我们所需要的数据的确切描述依然很有意义,我们能选择什么字段?服务器会返回哪种对象?这些对象下有哪些字段可用?这便是引入 schema 的原因。 ### 类型语言(Type Language) “GraphQL schema language” —— 它和 GraphQL 的查询语言很相似,让我们能够和 GraphQL schema 之间可以无语言差异地沟通。 ### 对象类型和字段(Object Types and Fields) ```graphql type Character { name: String! appearsIn: [Episode!]! } ``` ### 参数(Arguments) ```graphql type Starship { id: ID! name: String! length(unit: LengthUnit = METER): Float } ``` 所有参数必须具名传递 ### 查询和变更类型(The Query and Mutation Types) ``` schema { query: Query mutation: Mutation } ``` 每一个 GraphQL 服务都有一个 query 类型,可能有一个 mutation 类型。 ### 标量类型(Scalar Types) GraphQL 自带一组默认标量类型: * Int:有符号 32 位整数。 * Float:有符号双精度浮点值。 * String:UTF‐8 字符序列。 * Boolean:true 或者 false。 * ID:ID 标量类型表示一个唯一标识符,通常用以重新获取对象或者作为缓存中的键。ID 类型使用和 String 一样的方式序列化;然而将其定义为 ID 意味着并不需要人类可读型。 我们可以定义一个 Date 类型: scalar Date 然后就取决于我们的实现中如何定义将其序列化、反序列化和验证。例如,你可以指定 Date 类型应该总是被序列化成整型时间戳,而客户端应该知道去要求任何 date 字段都是这个格式。 ### 枚举类型(Enumeration Types) ```graphql enum Episode { NEWHOPE EMPIRE JEDI } ``` ### 列表和非空(Lists and Non-Null) type Character { name: String! myField: [String!] myField2: [String]! } myField: [String!],这表示数组本身可以为空,但是其不能有任何空值成员。用 JSON 举例如下: myField: null // 有效 myField: [] // 有效 myField: ['a', 'b'] // 有效 myField: ['a', null, 'b'] // 错误 myField2: [String]!,这表示数组本身不能为空,但是其可以包含空值成员: myField2: null // 错误 myField2: [] // 有效 myField2: ['a', 'b'] // 有效 myField2: ['a', null, 'b'] // 有效 ### 接口(Interfaces) ``` interface Character { id: ID! name: String! friends: [Character] appearsIn: [Episode]! } 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 ... on Droid { primaryFunction } } } ``` ### 联合类型(Union Types) [union-types](https://graphql.cn/learn/schema/#union-types) ### 输入类型(Input Types) ``` input ReviewInput { stars: Int! commentary: String } ``` 你可以像这样在变更(mutation)中使用输入对象类型: ``` mutation CreateReviewForEpisode($ep: Episode!, $review: ReviewInput!) { createReview(episode: $ep, review: $review) { stars commentary } } { "ep": "JEDI", "review": { "stars": 5, "commentary": "This is a great movie!" } } ``` ## 验证 [validation](https://graphql.cn/learn/validation/) ## 执行 GraphQL 查询中的每个类型的每个字段都由一个 resolver 函数支持,该函数由 GraphQL 服务器开发人员提供。当一个字段被执行时,相应的 resolver 被调用以产生下一个值。 如果字段产生标量值,例如字符串或数字,则执行完成。如果一个字段产生一个对象,则该查询将继续执行该对象对应字段的解析器,直到生成标量值。GraphQL 查询始终以标量值结束。 ```js Human: { name(obj, args, context, info) { return obj.name } } ``` 在这个例子中,对 name 字段的处理非常的清晰,name 字段对应的解析器被调用的时候,解析器回调函数的 obj 参数是由上层回调函数生成的 new Human 对象。在这个案例中,我们希望 Human 对象会拥有一个 name 属性可以让我们直接读取。 事实上,许多 GraphQL 库可以让你省略这些简单的解析器,假定一个字段没有提供解析器时,那么应该从上层返回对象中**读取和返回和这个字段同名的属性。** ## 内省 我们有时候会需要去问 GraphQL Schema 它支持哪些查询。GraphQL 通过内省系统让我们可以做到这点! ``` { __schema { types { name } } } { __schema { queryType { name } } } { __type(name: "Droid") { name kind } } { __type(name: "Droid") { name fields { name type { name kind } } } } ``` [introspection](https://graphql.cn/learn/introspection/) ## GraphQL核心概念 https://segmentfault.com/a/1190000014131950 ## contructing type 将graphsql的schema定义,从string方式转变为类型定义的方式,虽然代码量会上升,但是多了类型检查,便于维护。 ```js const schema = buildSchema(` type Account { id: ID name: String age: Int } type Query{ account(username: String): Account } `) ``` 上述代码转为3部分: ```js var AccountType = new graphql.GraphQLObjectType({ name: 'Account', fields: { id: {type: graphql.GraphQLID}, name: {type: graphql.QraphQLString}, age: {type: graphql.GraphQLInt} } }) var queryTYpe = new graphql.GraphQLObjectTpe({ name: 'Query' fields: { account: { type: AccountType, args: { id: {type: graphql.GraphQLID} }, resolve: function(_, {id}) { return { id: 1, name: "test", age: 18 } } } } }) var query = new graphql.GraphQLSchema({query: queryType}); ``` ## n+1 query 如下的query, authors Resolver 先进行 1 次query获取n个authors,然后books Resolver 再进行 n 次query,获取每本书的名字,这就是 n+1 query ```graphql { query { authors { name books { name } } } } ``` ### 如何解决?dataloader 主要思想为,减少数据库请求。 dataloader会定义一个时间段,在这个时间段内发起的多个请求,经过处理之后会合并为单个请求,比如 getBookByID(1) 和 getBookByID(2) 会合并为一个 getBooksByIDs(1, 2) 请求 [dataloader github](https://github.com/graphql/dataloader) go语言实现: [dataloader.v5](https://github.com/graph-gophers/dataloader/tree/v5.0.0) 默认的时间段为16毫秒: ```go func NewBatchedLoader(batchFn BatchFunc, opts ...Option) *Loader { loader := &Loader{ batchFn: batchFn, inputCap: 1000, wait: 16 * time.Millisecond, } ```
×
本文为博主原创,如需转载,请注明出处:
http://www.supperxin.com
返回博客列表