热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

GraphQL新手上路

GraphQL是什么?GraphQL既是一种用于API的查询语言也是一个满足你数据查询的运行时(来自:官方解释)理解起来就是,GraphQL有自己查询语法,

GraphQL新手上路

GraphQL是什么?

GraphQL 既是一种用于API的查询语言也是一个满足你数据查询的运行时(来自:官方解释)

理解起来就是,GraphQL有自己查询语法,发起的API请求中通过传递查询语句来告诉服务端需要哪些操作和具体数据字段,GraphQL定义了实现规范,各种的语言分别实现了GraphQL功能框架,通过框架可以对查询语法进行解释执行,然后返回数据输出给客户端

GraphQL新手上路


GraphQL的优势

以下所有查询和输出都是来自我的DEMO,DEMO的实现和源码Github地址下面会提到

语法特性满足各种需求

  • 支持多操作:query->查询,mutation->修改,规范是写在查询语句前,默认不写就是query
  • 支持参数,实现各种功能,比如:查询数据,排序,分页,... ...等
  • 语法其他特性,别名,片段,定义变量,指令,... ...等
# 查询语句-有参数
query{
  student(id:86){
    id
    name
    sclass{
      id
      num
      level
      heads
    }
  }
}
# 输出
{
  "data": {
    "student": {
      "id": 86,
      "name": "Emma",
      "sclass": {
        "id": 9,
        "num": 8,
        "level": 3,
        "heads": 68
      }
    }
  }
}
# 修改
mutation {
  update(id: 86, name: "66666") {
    rt
    msg
  }
}
# 输出
{
  "data": {
    "update": {
      "rt": 1,
      "msg": "bingo"
    }
  }
}

查询友好性,查询和输出关联

看查询语句是不是感觉有点儿JSON的味道?查询语法类JSON格式,前后端都可以很容易上手,查询语句和输出数据有紧密的关联性,通过分析查询语句就知道输出的数据内容字段有哪些


灵活性,请求你所要的数据,不多不少

可以自定义查询语句来获取需要使用的字段,避免无用字段的输出,减少不必要数据块/数据字段查询逻辑

多字段

# 查询语句
query{
  students{
    id
    name
    classid
    sclass{
      id
      num
      level
      heads
    }
  }
}
# 输出
{
  "data": {
    "students": [
       {
        "id": 19,
        "name": "Savannah",
        "classid":22,
        "sclass": {
          "id": 22,
          "num": 6,
          "level": 4,
          "heads": 57
        }
      },
      {
        "id": 34,
        "name": "Ariana",
        "classid":33,
        "sclass": {
          "id": 33,
          "num": 3,
          "level": 4,
          "heads": 57
        }
      }
    ]
  }
}

去掉了不使用的字段输出,少了字段sclass,就可以不进行sclass数据查询

# 查询语句
query{
  students{
    id
    name
  }
}
# 输出
{
  "data": {
    "students": [
      {
        "id": 19,
        "name": "Savannah"
      },
      {
        "id": 34,
        "name": "Ariana"
      }
    ]
  }
}

API演进,无需划分版本

API版本迭代无需要进行版本号区分,添加字段不影响现有查询,请求发起者可以自己定义想要的查询信息

# Say No
http://api.xxx.com/student/v1/
http://api.xxx.com/student/v2/
# ... 

自检性,可查询输出所有定义

这个是GraphQL一个很Nice的特性,就是GraphQL服务API可以通过语句查询出它所支持的类型,开发可以不需要花时间写API文档,GraphQL直接帮助开发者快速了解API。

# 查询语句
{
  __type(name: "MStudentType") {
    kind
    name
    fields {
      name
      description
      type {
        name
      }
    }
  }
}
# 输出
{
  "data": {
    "__type": {
      "kind": "OBJECT",
      "name": "MStudentType",
      "fields": [
        {
          "name": "id",
          "description": "学号",
          "type": {
            "name": null
          }
        },
        {
          "name": "name",
          "description": "学生名",
          "type": {
            "name": null
          }
        },
        {
          "name": "age",
          "description": "年龄",
          "type": {
            "name": null
          }
        },
        {
          "name": "birthdate",
          "description": "生日",
          "type": {
            "name": null
          }
        },
        {
          "name": "sclass",
          "description": "班级信息",
          "type": {
            "name": "MClassType"
          }
        }
      ]
    }
  }
}

基于自检性,GraphQL开源了辅助工具GraphiQL,方便GraphQL接口调试和自动生成接口文档

  • GraphQL辅助工具:GraphiQL,可以调试查询语句,并对接口定义的schema进行文档可视化展示
    • 查询语句进行感知
    • 错误提示
    • 语句格式化
    • 执行查询
    • 查看接口定义的schema文档信息

graphql-dotnet开源项目里的GraphiQL要接入自己开发GraphQL接口,还需要进行简单的修改调整,后面会说到


.NET下的入门教程

  • 构建ASP.NET MVC5 WebAPI 项目
  • NutGet引入程序包
    • GraphQL
    • GenFu,用于初始化测试数据
  • 基于GraphQL简单实现一个学生查询API
    • 支持查询学生信息列表
    • 支持查询学生的班级信息
    • 支持查询学号对应的学生信息
    • 支持修改学生名字

定义【数据类】MStudent.cs(学生类),MClass.cs(班级类),MResult.cs(执行结果类)


public class MStudent {
    /// 
    /// 学号
    /// 
    public int Id { get; set; }
    /// 
    /// 名字
    /// 
    public string Name { get; set; }
    /// 
    /// 年龄
    /// 
    public int Age { get; set; }
    /// 
    /// 所在班级编号
    /// 
    public int ClassId { get; set; }
    /// 
    /// 生日
    /// 
    public DateTime Birthdate { get; set; }
    /// 
    /// 班级
    /// 
    public MClass SClass { get; set; }
}

public class MClass {
    public int Id { get; set; }
    /// 
    /// 年级
    /// 
    public int Level { get; set; }
    /// 
    /// 第几班
    /// 
    public int Num { get; set; }
    /// 
    /// 总人数
    /// 
    public int Heads { get; set; }
}

public class MResult {
    /// 
    /// 输出结果,0=失败,1=成功
    /// 
    public int rt { get; set; }
    /// 
    /// 说明信息
    /// 
    public string msg { get; set; }
}

定义GraphType类 MStudentType,MClassType,MResultType 继承ObjectGraphType ,TSourceType泛型对应到【数据类】
构造函数里通过Field去添加可以被查询的数据字段,包括:描述以及字段内容获取的处理方法,等


public class MStudentType : ObjectGraphType {
    private static BStudent _bll { get; set; }
    public MStudentType() {
        if (_bll == null) _bll = new BStudent();
        Field(d => d.Id).Description("学号");
        Field(d => d.Name).Description("学生名");
        Field(d => d.Age).Description("年龄");
        Field(d => d.Birthdate).Description("生日");
        Field("sclass", resolve: d => {
            //缓存中已经存在就直接返回
            if (d.Source.SClass != null) return d.Source.SClass;
            //从DB/缓存中获取数据
            var classId = d.Source?.ClassId ?? 0;
            if (classId > 0) d.Source.SClass = _bll.GetClass(d.Source.ClassId);
            return d.Source.SClass;
        },description:"班级信息");
    }
}

public class MClassType : ObjectGraphType {
    public MClassType() {
        Field(d => d.Level).Description("年级");
        Field(d => d.Heads).Description("人数");
        Field(d => d.Id).Description("编号");
        Field(d => d.Num).Description("班级");
    }
}

public class MResultType : ObjectGraphType {
    public MResultType() {
        Field(d => d.rt);
        Field(d => d.msg);
    }
}

定义Schema的操作类(query/mutation),继承 ObjectGraphType,有:StudentQuery,StudentMutation


public class StudentQuery : ObjectGraphType {
        public StudentQuery(BStudent bll) {
            //查询-有参数id
            Field("student", arguments: new QueryArguments(new QueryArgument() {
                Name = "id"
            }), resolve: d => {
                var id = d.Arguments["id"].GetInt(0, false);
                return bll.GetModel(id); ;
            });
            //查询-列表
            Field>("students", resolve: d => {
                return bll.GetStudents();
            });
        }
    }
}

public class StudentMutation : ObjectGraphType {
    public StudentMutation(BStudent bll) {
        Field("update", arguments: new QueryArguments(
            new QueryArgument {
                Name = "id"
            },
            new QueryArgument {
                Name = "name"
            }
        ), resolve: (d) => {
            var id = d.Arguments["id"].GetInt(0, false);
            var name = d.Arguments["name"].GetString("");
            if (id <= 0) return new MResult {
                rt = 0,
                msg = "非法学号"
            };
            if (name.IsNullOrWhiteSpace()) return new MResult {
                rt = 0,
                msg = "非法名字"
            };
            var isSc = bll.UpdateName(id, name);
            if (!isSc) return new MResult {
                rt = 0,
                msg = "更新失败"
            };
            return new MResult {
                rt = 1,
                msg = "bingo"
            };
        });
    }
}

在控制器里添加接口,构造Schema对象,根据查询条件解析执行返回结果输出
Query = StudentQuery,Mutation = StudentMutation

/// 
/// graphql demo 接口
/// 
/// 
[HttpPost]
[Route("query")]
public object Test_Query() {
    var r = HttpContext.Current.Request;
    var query = r.GetF("query");
    var bll = new BStudent();
    var schema = new Schema { Query = new StudentQuery(bll), Mutation = new StudentMutation(bll) };
    var result = new DocumentExecuter()
        .ExecuteAsync(optiOns=> {
            options.Schema = schema;
            options.Query = query;
        }).GetAwaiter();
    var json = new DocumentWriter(indent: true).Write(result);
    return result.GetResult();
}

GraphiQL工具的接入

  • Git Clone graphql-dotnet
  • 安装NodeJS环境
  • 命令工具CMD打开graphql-dotnet/src/GraphQL.GraphiQL/ 执行下面命令
    • npm install -g yarn
    • yarn install
    • yarn start
  • 运行graphql-dotnet/src/GraphQL.GraphiQL 就可以启动:http://localhost:47080/
  • 根据自己的情况调整:graphql-dotnet/src/GraphQL.GraphiQL/app/app.js 脚本,如下面贴出的代码
    • url=graphql接口地址
    • 如果需要投入生产使用,可以把接口地址进行url传入,或者支持输入框输入地址,不固定接口地址
  • 每次调整完需要重新执行 yarn start,前端会使用webpack进行打包操作,执行完成后刷新页面即可

//调整如下
import React from 'react';
import ReactDOM from 'react-dom';
import GraphiQL from 'graphiql';
import axios from 'axios';
import 'graphiql/graphiql.css';
import './app.css';

function graphQLFetcher(graphQLParams) {
    console.log(graphQLParams["query"]);
    return axios({
        method: 'post',
        url: "http://127.0.0.1:5656/query",//window.location.origin + '/api/graphql',
        data: "query=" + graphQLParams["query"],
        headers: { 'Content-Type': 'application/x-www-form-urlencoded' }
    }).then(resp => resp.data);
}
ReactDOM.render(, document.getElementById('app'));

GraphQL新手上路

总结

  • 对于应用我觉得可以尝试使用到新项目需求中,或者现有合适应用场景进行重构,等服务运行稳定,并且开发上手后即可进行大范围的使用
  • 对于RestFul和GraphQL的比较,我觉得没有最好的协议,只有最合适的场景

资源

  • Demo源码:
    • Demo代码到我的Gtihub项目(GraphQLDemo)
  • 学习资料
    • 知乎-什么是GraphQL
    • GraphQL语法入门
    • GraphQL中文官网
    • How To GraphQL
    • GraphQL 搭配 Koa 最佳入门实践

首发于本人独立博客


推荐阅读
  • 本文讨论了如何使用Web.Config进行自定义配置节的配置转换。作者提到,他将msbuild设置为详细模式,但转换却忽略了带有替换转换的自定义部分的存在。 ... [详细]
  • 如何查询zone下的表的信息
    本文介绍了如何通过TcaplusDB知识库查询zone下的表的信息。包括请求地址、GET请求参数说明、返回参数说明等内容。通过curl方法发起请求,并提供了请求示例。 ... [详细]
  • YOLOv7基于自己的数据集从零构建模型完整训练、推理计算超详细教程
    本文介绍了关于人工智能、神经网络和深度学习的知识点,并提供了YOLOv7基于自己的数据集从零构建模型完整训练、推理计算的详细教程。文章还提到了郑州最低生活保障的话题。对于从事目标检测任务的人来说,YOLO是一个熟悉的模型。文章还提到了yolov4和yolov6的相关内容,以及选择模型的优化思路。 ... [详细]
  • Spring源码解密之默认标签的解析方式分析
    本文分析了Spring源码解密中默认标签的解析方式。通过对命名空间的判断,区分默认命名空间和自定义命名空间,并采用不同的解析方式。其中,bean标签的解析最为复杂和重要。 ... [详细]
  • 开发笔记:加密&json&StringIO模块&BytesIO模块
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了加密&json&StringIO模块&BytesIO模块相关的知识,希望对你有一定的参考价值。一、加密加密 ... [详细]
  • 阿,里,云,物,联网,net,core,客户端,czgl,aliiotclient, ... [详细]
  • 知识图谱——机器大脑中的知识库
    本文介绍了知识图谱在机器大脑中的应用,以及搜索引擎在知识图谱方面的发展。以谷歌知识图谱为例,说明了知识图谱的智能化特点。通过搜索引擎用户可以获取更加智能化的答案,如搜索关键词"Marie Curie",会得到居里夫人的详细信息以及与之相关的历史人物。知识图谱的出现引起了搜索引擎行业的变革,不仅美国的微软必应,中国的百度、搜狗等搜索引擎公司也纷纷推出了自己的知识图谱。 ... [详细]
  • 使用在线工具jsonschema2pojo根据json生成java对象
    本文介绍了使用在线工具jsonschema2pojo根据json生成java对象的方法。通过该工具,用户只需将json字符串复制到输入框中,即可自动将其转换成java对象。该工具还能解析列表式的json数据,并将嵌套在内层的对象也解析出来。本文以请求github的api为例,展示了使用该工具的步骤和效果。 ... [详细]
  • ZSI.generate.Wsdl2PythonError: unsupported local simpleType restriction ... [详细]
  • 在重复造轮子的情况下用ProxyServlet反向代理来减少工作量
    像不少公司内部不同团队都会自己研发自己工具产品,当各个产品逐渐成熟,到达了一定的发展瓶颈,同时每个产品都有着自己的入口,用户 ... [详细]
  • Android JSON基础,音视频开发进阶指南目录
    Array里面的对象数据是有序的,json字符串最外层是方括号的,方括号:[]解析jsonArray代码try{json字符串最外层是 ... [详细]
  • Spring常用注解(绝对经典),全靠这份Java知识点PDF大全
    本文介绍了Spring常用注解和注入bean的注解,包括@Bean、@Autowired、@Inject等,同时提供了一个Java知识点PDF大全的资源链接。其中详细介绍了ColorFactoryBean的使用,以及@Autowired和@Inject的区别和用法。此外,还提到了@Required属性的配置和使用。 ... [详细]
  • uniapp开发H5解决跨域问题的两种代理方法
    本文介绍了uniapp开发H5解决跨域问题的两种代理方法,分别是在manifest.json文件和vue.config.js文件中设置代理。通过设置代理根域名和配置路径别名,可以实现H5页面的跨域访问。同时还介绍了如何开启内网穿透,让外网的人可以访问到本地调试的H5页面。 ... [详细]
  • 本文介绍了如何使用JSONObiect和Gson相关方法实现json数据与kotlin对象的相互转换。首先解释了JSON的概念和数据格式,然后详细介绍了相关API,包括JSONObject和Gson的使用方法。接着讲解了如何将json格式的字符串转换为kotlin对象或List,以及如何将kotlin对象转换为json字符串。最后提到了使用Map封装json对象的特殊情况。文章还对JSON和XML进行了比较,指出了JSON的优势和缺点。 ... [详细]
  • 图像因存在错误而无法显示 ... [详细]
author-avatar
keleesen
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有