Baas接口标准(二)——对象类型定义规则之用法、定义规则、字段参数的用法之标量类型、枚举类型、列表和非空、输入类型 & 服务端开发-resolver函数参数用法之parent参数、context参数
对象类型定义规则
对象类型定义与字段
GraphQL提供一套完善的类型系统,可以约束服务端可以提供哪些数据类型供客户端查询使用
# 通过type关键字定义类型,type之后是类型名称(自定义名称)
type Course {
cname: String
score: Float
}
type Student {
name: String
scores: [Course]
}
- 注意事项
- 花括号中是对象的字段信息
- 属性名称是自定义的
- 属性名后面的类型为标量类型(内置类型)
- GraphQL使用#进行注释
基本参数
对象类型上的每一个字段都可能有零个或者多个参数,可以按照条件查询数据
type Query {
hello: String
# 定义字段参数,可以有默认值
stu(n: Int = 12): Student
}
# 获取参数(通过resolver函数的第二个参数获取客户端传递的参数数据)
const resolvers = {
Query: {
stu: (obj, args) => {
console.log(args)
}
},
};
{
# 客户端字段参数传递
stu(n: 13) {
name
age
}
}
- 注意事项
- 参数可以指定默认值,如果有默认值,那么参数就是可选的
- 客户端参数通过resolver函数的第二个参数获取
内置类型
- 查询和变更类型
内置类型中有两个特殊的类型:Query和Mutation
每一个GraphQL服务有右一个Query类型,也可能有一个Mutation类型,这两个类型本质上也是对象类型,只不过有一点区别:它们作为客户端访问的入口
- 标量类型
- Int
- Float
- String
- Boolean
- ID 唯一标识符,不需要人类可度
标量类型用于表示基本的字段数据,表示查询数据的叶子节点
- 枚举类型
枚举类型是一种特殊的标量,它限制在一个特殊的可选值集合内。
enum Favour {
SWIMING
CODING
SINGING
}
上述定义表示只能获取三种值之一,其他类型的值是不可以的
- 列表和非空
- []表示列表
- 叹号表示非空
type Student {
name: String!
scores: [Score!]!
}
myField: [String!] 表示数组本身可以为空,但是其不能有任何空值成员
myField: [String]! 表示数组本身不能为空,但是其可以包含空值成员
输入类型
参数也可以是复杂类型,主要用于变更Mutation场景(需要客户端传递输入类型)
# 定义输入类型
input UserInput {
uname: String
pwd: String
}
定义Mutation,可以用于接收客户端传递的input类型数据
# 接收客户端传递的input类型参数
type Mutation {
addUserByInput(userInput: UserInput): User
}
# 处理客户端传递的input参数
const resolvers = {
Mutation: {
addUserByInput: (obj, args) => {
// args可以获取客户端传递的input类型数据
return {
id: 123,
uname: args.uname,
pwd: args.pwd
}
}
}
}
# 客户端查询操作
mutation {
addUserByInput(userInput: {
uname: "lisi",
pwd: "123"
}) {
id
username
}
}
- 注意事项
- input类型主要用于变更操作的数据传递
数据解析规则详解
resolver函数参数用法
resolves用于给类型字段提供实际数据
- resolve函数参数
- parent 上一级对象,如果字段属于根节点查询类型通常不会被使用。
args
可以提供在 GraphQL 查询中传入的参数。context
会被提供给所有解析器,并且持有重要的上下文信息比如当前登入的用户或者数据库访问对象。info
一个保存与当前查询相关的字段特定信息以及 schema 详细信息的值
// 服务端数据解析
const resolvers = {
Query: {
hello: () => "Hello World"
},
Mutation: {
addInfo: (parent, args, context, info) => {
// parent表示当前字段的父级对象
console.log(parent);
// args表示客户端传递过来的参数
console.log(args);
// context可以用于操作数据源
console.log(context);
},
}
};
- parent 参数用法
// 类型定义
type Student {
sname: String
age: Int
}
// 数据解析
const resolvers = {
Student: {
// 提供字段的resolver函数,如果不提供,会默认生成
sname: (parent) => {
return parent.sname
}
},
stu: (parent) => {
return {
sname: 'lisi',
age: 12
}
}
};
- 注意事项
- 通过resolver函数的第一个参数parent可以获取父级对象
- 如果字段类型是标量类型,会有一个默认的resolver函数
- 默认的resolver函数,返回父级对象的字段数据
resolver函数对接数据源
通过context参数更加方便的对接数据源(数据库、文件、第三方接口),包括异步操作
- context基本用法
// context可以用于获取数据源对象
const context = () => {
return {
db: 'dbObj'
}
}
const server = new ApolloServer({ typeDefs, resolvers, context });
// 在resolver函数中可以通过context对象操作数据源
const resolvers = {
Query: {
hello: (parent, args, context) => {
// 通过context可以获取数据源操作对象
let ret = context.db;
}
}
};
- 读取文件数据业务模块
// db.js代码:从文件中读取数据,本质上与从数据库读取数据类似,都可以是异步操作
const path = require('path');
const fs = require('fs');
module.exports.getData = () => {
const dataPath = path.join(__dirname, 'data.json');
return new Promise((resolve, reject) => {
fs.readFile(dataPath, (err, data) => {
if(err) {
reject('error');
}
resolve(data);
})
})
}
- 通过context获取数据源操作的对象
// 从文件中读取数据作为数据源,db.getData()返回Promise实例对象
const db = require('./db.js');
const context = ({req}) => {
return { db: db }
}
const resolvers = {
Query: {
hello: async (obj, args, context, info) => {
let ret = await context.db.getData();
return ret;
}
}
}
const server = new ApolloServer({ typeDefs, resolvers, context });
- 注意事项
- context参数主要用于提供数据源相关对象,方便进行数据操作(数据获取与变更)