GraphQL 客户端开发

760 阅读4分钟

4.1 基本查询

按需获取需要的数据

// 定义类型
const typeDefs = gql`
  type Hero {
    name: String
    age: Int
  }

  # 查询类型
  type Query {
    hero: Hero
  }

`;

// resolver 函数
const resolvers = {
  Query: {
    hero: () => {
      return {
        name: 'nordon',
        age: 18
      }
    }
  },
};

// 查询 hero 对象的 name 属性
{
	hero {
		name
	}
}

// 结果
{
  "data": {
    "hero": {
      "name": "nordon"
    }
  }
}
  • 注意事项
    • GraphQL 只有一个utl地址、客户端查询的所有信息都通过该地址获取数据
    • 可以更具需要按照实际的需求获取特定的数据

4.2 操作名称

有多个操作时、操作名称是必须的、为了调试方便最好添加操作名

  • 规则 — 操作类型 操作名称(操作名称自定义)
  • 操作类型主要有两种
    • query 用于查询
    • mutation 用于数据变更 — CRUD
# 定义数据类型
const typeDefs = gql`

  # 输入类型
  input UserInfo {
    name: String
    pwd: String
  }

  # 用户类型
  type User {
    id: ID
    name: String
    pwd: String
  }

  # 变更类型
  type Mutation {
    addUser(userInfo: UserInfo): User
  }

  # 查询类型
  type Query {
    hello: String
    msg: String
  }

`;



// 3. 解析数据类型对应的具体数据
const resolvers = {
  Query: {
    hello: () => 'hi query',
    msg: () => 'msg query'
  },
  Mutation: {
    addUser: (parent, args) => {
      return {
        id: uuid(),
        name: args.userInfo.name,
        pwd: args.userInfo.pwd
      }
    }
  }
};

# 需要定义 每个查询的类型名称、存在多个查询前面必须存在 query、

query helloInfo {
  hello
}

query msgInfo {
  msg
}

mutation addUser {
  addUser(userInfo: {
    name: "nordon",
    pwd: "123123"
  }){
    id
    name
    pwd
  }
}

01.png

  • 注意事项
    • 推荐所有的查询和变更操作都添加操作名称

4.3 查询参数

有时候需要根据特定的条件查询数据、此时可以使用查询参数

const typeDefs = gql`
  # 学生类型
  type Student {
    name: String
    age: Int
    gender: Boolean
  }

  # 查询类型
  type Query {
    hello: String
    stu(id: Int, name: String): Student
  }

`;

const resolvers = {
  Query: {
    hello: () => 'Hello world!',
    stu: (parent, args) => {
      let stu = null;

      if(args.id === 1 && args.name === 'nordon'){
        stu = {
          name: 'norodn',
          age: 18,
          gender: true
        }
      }else {
        stu = {
          name: 'null',
          age: 0,
          gender: false
        }
      }

      return stu
    }
  },
};
query stu {
  stu(id: 1, name: "nordon"){
    name
    age
    gender
  }
}

02.png

  • 注意事项
    • 查询字段可以携带参数、并且可以携带多个参数、参数之间通过逗号隔开

4.4 变量

有时字段的参数需要动态提供、而不是固定的值、此时就可以使用变量、类似函数中的形参


// 定义数据类型
const typeDefs = gql`
  # 课程类型
  type Course {
    cname: String
    score: Float
  }

  # 学生类型
  type Student {
    id: ID
    sname: String
    age: Int
    scores(num: Float): [Course]
  }

  # 查询类型
  type Query {
    stu(id: Int): Student
  }

`;

// 解析数据类型对应的具体数据
const resolvers = {
  Student: {
    scores: (parent, args) => {
      return parent.scores && parent.scores.filter(item => item.score > args.num)
    }
  },
  Query: {
    stu: (parent, args) => {
      if(args.id === 1){
        return {
          id: uuid(),
          sname: 'nordon',
          age:18,
          scores: [{
            cname: '数学',
            score: 66
          },{
            cname: '英语',
            score: 55
          },{
            cname: '语文',
            score: 77
          }]
        }
      }else{
        return {
          id:0,
          sname: 'null',
          scores: null
        }
      }
    }
  },
};

03.png

04.png

  • 注意事项
    • 变量类型必须是标量、枚举型、输入对象类型
    • 变量可以有默认值 ($id: Int = 1)

4.5 指令

有时候查询的字段数量不是固定的、此时可以通过制定的方式进行控制

  • 两个指令
    • @include(if: Boolean) 仅在参数为 true 时包含此字段
    • @skip(if: Boolean) 如果参数为 true 时跳过此字段

// 定义数据类型
const typeDefs = gql`
  # 学生类型
  type Student {
    id: ID
    name: String
    gender: Boolean
  }

  # 查询类型
  type Query {
    stu(id: Int): Student
  }

`;

// 解析数据类型对应的具体数据
const resolvers = {
  Query: {
    stu: (parent, args) => {
      if(args.id === 1){
        return {
          id: uuid(),
          name: 'nordon',
          gender: true
        }
      }else{
        return {
          id: uuid(),
          name: 'wangyao',
          gender: false
        }
      }
    }
  },
};
# 如果指令使用的、需要显示的传递字段、需要在后面增加一个!叹号
query stu($id: Int, $gender: Boolean!){
  stu(id: $id){
    id
    name
    gender @include(if: $gender)
    # gender @skip(if: $gender)
  }
}

05.png

06.png

  • 注意事项
    • 可以通过这两个指令动态的控制查询的字段数量
    • 指令用到的变量定义时需要添加!叹号、强制必须提供该值

4.6别名

通过不同的参数来查询相同的字段信息、比如查询学生的数学和英语成绩


// 定义数据类型
// Query 类型是默认客户端查询的类型、并且该类型在服务端必须存在并且是唯一的
const typeDefs = gql`
  # 课程类型
  type Course {
    cname: String
    score: Float
  }

  # 学生类型
  type Student {
    id: ID
    sname: String
    age: Int
    scores(cname: String): [Course]
  }

  # 查询类型
  type Query {
    stu: Student
  }
`;
01.png
// 解析数据类型对应的具体数据
const resolvers = {
  Student:{
    scores: (parent, args) => {
      if(args.cname === '数学' || args.cname === '语文'){
        return parent.scores.filter(item => item.cname === args.cname)
      }else{
        return parent.scores
      }
    }
  },
  Query: {
    stu: (parent, args) => {
      return {
        id: uuid(),
        sname: 'nordon',
        age:18,
        scores: [{
          cname: '数学',
          score: 66
        },{
          cname: '英语',
          score: 55
        },{
          cname: '语文',
          score: 77
        }]
      }
    }
  },
};
query stu{
  stu{
    id
    sname
    math: scores(cname: "数学"){
      cname
      score
    },
    china: scores(cname: "语文"){
      cname
      score
    },
    all: scores{
      cname
      score
    }
  }
}

07.png

  • 注意事项
    • 可以通过别名的方式获取特定某几项数据(查询接口的数据格式相同)

4.7 变更

改变服务器数据需要用到mutation操作

// 2. 定义数据类型
// Query 类型是默认客户端查询的类型、并且该类型在服务端必须存在并且是唯一的
const typeDefs = gql`
  #输入类型
  input UserInfo {
    uname: String
    pwd: String
  }

  # 用户类型
  type User {
    id: ID
    uname: String
    pwd: String
  }

  # 变更类型
  type Mutation {
    addUserByParams(uname: String, pwd: String): User
    addUserByInput(userInput: UserInfo): User
  }

  # 查询类型
  type Query {
    hello: String
  }

`;

// 3. 解析数据类型对应的具体数据
const resolvers = {
  Query: {
    hello: () => 'Hello world!'
  },
  Mutation: {
    addUserByParams: (parent, args) => {
      return {
        id: uuid(),
        uname: args.uname,
        pwd: args.pwd
      }
    },
    addUserByInput: (parent, args) => {
      return {
        id: uuid(),
        uname: args.userInput.uname,
        pwd: args.userInput.pwd
      }
    }
  }
};
mutation addUserByParams {
  addUserByParams(uname: "nordon", pwd: "123123"){
    id
    uname
    pwd
  }
}

mutation addUserByInput($userInput: UserInfo){
  addUserByInput(userInput: $userInput){
    id
    uname
    pwd
  }
}

08.png

  • 注意事项
    • 通过 mutation 关键字实现变更操作
    • userInput 变量并非标量、而是一个输入类型
    • 参数的传递可以通过普通参数、也可以使用输入类型、一般较为复杂的数据采用输入类型

参考网站

grapgQL官网

apolloserver官网