陌小路的个人博客 陌小路的个人博客
首页
  • 技术专区

    • 面试
    • Vue
    • Electron
    • TypeScript
    • Serverless
    • GraphQL
  • 我的秋招之旅
  • 2019年终总结
Todo
收藏夹
关于作者
GitHub

陌小路

前端切图仔
首页
  • 技术专区

    • 面试
    • Vue
    • Electron
    • TypeScript
    • Serverless
    • GraphQL
  • 我的秋招之旅
  • 2019年终总结
Todo
收藏夹
关于作者
GitHub
  • Vue

  • React

  • 面试

  • Electron

  • Serverless

  • GraphQL

    • 介绍
    • 类型
    • 查询与修改
      • 实战
    • TypeScript

    • RxJS

    • 工程化

    • Webpack

    • Nestjs

    • WebRTC & P2P

    • Docker

    • Linux

    • Git

    • Svelte

    • 踩坑日记 & 小Tips

    • 其他

    • technology
    • GraphQL
    陌小路
    2020-12-05

    查询与修改

    # Query

    工作流

    从这里开始就准备开始接触实际的操作了,Query就对比于RESTful来说就类似于Router,它是作为入口提供给客户端调用查询数据的。

    我们再来看看详细的定义方式:

    type Account {
        name: String
        age: Int,
        sex: String,
        salary(city: String): Int
    }
    
    type Query {
        name: String
        age: Int,
        account(username: String!): Account
        accounts: [Account]
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13

    我们这里可以先忽略字段后面括号内容,这个属于Argument的内容,详细可以参考Argument部分。

    从代码中来看,这里定义了Query类型,它是作为查询入口而存在的,同时这个对象中定义了多个字段,这些字段将暴露给客户端进行查询返回,并且这些字段不限于标量类型联合类型等等,不仅如此,定义在Query中的这些字段都要有他们各自的resolver,因为这里只是定义了他们的结构,具体返回值和逻辑部分需要有特定的resolver来处理,具体参考下面resolver部分。

    那么客户端又是怎么做到针对这些字段进行查询的呢?其实也很简单,直接按照他的结构进行一一对应查询即可,具体实现如下:

    query {
        account(username: "小李子") {
            name
            sex
            age
        }
        age,
        name
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9

    如上所示,我们可以按照我们想要的字段进行查询,我们需要什么字段就在对应的结构中写上字段名,那么服务器接收到请求之后就会按照你想要的仅仅返回你定义的查询字段,其他的都不会返回。

    这里有一个注意点,如果你的目标对象不是原始类型,而是一个对象,那么你必须标识你需要这个对象上的特定字段,也就是说必须精确到标量类型,否则就会出错,比如上面的account字段(这里忽略传参逻辑,后面会说),这个account对象定义的类型是Account,而Account类型具有name、age、sex、salary字段,那你在查询的时候,必须指定这个字段对象中的值,如果这个值还是对象,那你就还必须循环上述步骤直至拿到标量类型为止。

    # Argument

    关于参数,我们应该也很熟悉了,不就是类似于函数一样的传参。话虽如此,但是这里还是有点区别的。

    我们从代码层次来看GraphQL中怎么实现传参的:

    {
    	salary(city: String!): Int
    }
    
    1
    2
    3

    首先上面这个是在服务端定义结构的时候的写法,也比较好理解,也就是想要获取这个字段的值,那么你就必须传递这个参数(因为加了!,所以必须传),具体的这个参数怎么接收怎么处理,Resolver部分会提到,然后我们再来看客户端怎么进行查询传参的:

    query {
    	salary(city: "上海") 
    }
    
    1
    2
    3

    是不是也很好理解,只要参数名与你在服务端定义的参数名一致就可以了,然后后面给定具体的值。

    # Resolver

    对于GraphQL来说,它只有一个入口点,也就是根节点,查询一般都是从这个Root开始。

    假设有这样一个Schema:

    type UserInfo {
    	name: String
    	age: Int
    }
    type Query {
    	userinfo(userId: Int): UserInfo
    }
    
    1
    2
    3
    4
    5
    6
    7

    而对应的客户端查询语句如下:

    query {
    	userinfo(userId: 666): {
    		name
    		age
    	}
    }
    
    1
    2
    3
    4
    5
    6

    为了正常的响应给客户端这些字段的数据,那么我们就需要给特定的字段编写它的resolver。比如,上述的userinfo对应的实际数据其实就是由一个resolver进行处理返回的,一个resolver一般是一个对应的是一个函数,参数分别为:

    • obj 代表上一个对象;
    • args 查询参数;
    • context 上下文,类似于Koa的ctx;

    那么如何编写上述userinfo字段的resolver呢:

    const root = {
    	userinfo: function(obj, args, context) {
    		const userId = args.userId;
    		return {
    			name: '李明' + userId,
    			age: 18
    		}
    	}
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9

    这里忽略了这些数据的获取方式,直接写死的,而在实际项目中,这些字段的数据来源可以是数据库或者是其他RPC调用等等方式。同时我们应该也能注意到,我们在对需要传参的字段做处理的时候,直接可以从args中拿到对应的参数值,然后做逻辑处理返回。

    在编写完resolver后,这个字段才能在查询的时候拿到对应的值。

    # Mutation

    在讲解完Query和Resolver之后,相信大家对基本的查询交互代码编写已经有所了解,那么现在就继续讲解怎么修改数据吧。

    在开始讲解修改数据之前我们需要想想,如果我们需要修改某个用户的信息,我们是不是需要把新信息作为参数传递过去,那么这个参数类型势必就不是一个标量类型能够表示的了,所以就需要用到我们上面提到过的输入类型来进行传参。

    # 定义输入类型传参

    首先先定义schema

    type Account {
        name: String
        age: Int,
        sex: String,
        salary(city: String): Int
    }
    
    input AccountInput {
        name: String
        age: Int,
        sex: String
    }
    
    type Mutation {
        createAccount(input: AccountInput): Account
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16

    这里与Query不同的是,它的名字需要改成Mutation,Query与Mutation这两个名字是指定的,不能更改。

    我们从代码上看,其实和Query传参区别不大,唯一的区别在于参数的类型由之前的String变成现在了AccountInput,也就是从一个标量类型变成了一个对象类型,而定义输入类型的方式也从type变成了input。

    然后再来看看客户端传参方式:

    mutation {
      createAccount(input: {
        name: "李四"
        age: 10
        sex: "女"
      }) {
        name
      }
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9

    其实这里和上述的传参方式没啥区别,唯一的不同就是类型的转变,这里变成了对象方式的传参。

    编辑
    上次更新: 2023/11/25, 4:11:00
    类型
    实战

    ← 类型 实战→

    最近更新
    01
    github加速
    01-01
    02
    在线小工具
    01-01
    03
    Lora-Embeddings
    11-27
    更多文章>
    Theme by Vdoing | Copyright © 2020-2024 STDSuperman | MIT License
    • 跟随系统
    • 浅色模式
    • 深色模式
    • 阅读模式