GraphQL 既是一种用于API的查询语言也是一个知足你数据查询的运行时(来自:官方解释)javascript
理解起来就是,GraphQL有本身查询语法,发起的API请求中经过传递查询语句来告诉服务端须要哪些操做和具体数据字段,GraphQL定义了实现规范,各类的语言分别实现了GraphQL功能框架,经过框架能够对查询语法进行解释执行,而后返回数据输出给客户端css
如下全部查询和输出都是来自个人DEMO,DEMO的实现和源码Github地址下面会提到前端
语法特性知足各类需求java
# 查询语句-有参数 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" } } }
查询友好性,查询和输出关联react
看查询语句是否是感受有点儿JSON的味道?查询语法类JSON格式,先后端均可以很容易上手,查询语句和输出数据有紧密的关联性,经过分析查询语句就知道输出的数据内容字段有哪些webpack
灵活性,请求你所要的数据,很少很多ios
能够自定义查询语句来获取须要使用的字段,避免无用字段的输出,减小没必要要数据块/数据字段查询逻辑git
多字段github
# 查询语句 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数据查询web
# 查询语句 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-dotnet开源项目里的GraphiQL要接入本身开发GraphQL接口,还须要进行简单的修改调整,后面会说到
定义【数据类】MStudent.cs(学生类),MClass.cs(班级类),MResult.cs(执行结果类)
public class MStudent { /// <summary> /// 学号 /// </summary> public int Id { get; set; } /// <summary> /// 名字 /// </summary> public string Name { get; set; } /// <summary> /// 年龄 /// </summary> public int Age { get; set; } /// <summary> /// 所在班级编号 /// </summary> public int ClassId { get; set; } /// <summary> /// 生日 /// </summary> public DateTime Birthdate { get; set; } /// <summary> /// 班级 /// </summary> public MClass SClass { get; set; } } public class MClass { public int Id { get; set; } /// <summary> /// 年级 /// </summary> public int Level { get; set; } /// <summary> /// 第几班 /// </summary> public int Num { get; set; } /// <summary> /// 总人数 /// </summary> public int Heads { get; set; } } public class MResult { /// <summary> /// 输出结果,0=失败,1=成功 /// </summary> public int rt { get; set; } /// <summary> /// 说明信息 /// </summary> public string msg { get; set; } }
定义GraphType类 MStudentType,MClassType,MResultType 继承ObjectGraphType<TSourceType> ,TSourceType泛型对应到【数据类】
构造函数里经过Field去添加能够被查询的数据字段,包括:描述以及字段内容获取的处理方法,等
public class MStudentType : ObjectGraphType<MStudent> { 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<MClassType>("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<MClass> { 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<MResult> { 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<MStudentType>("student", arguments: new QueryArguments(new QueryArgument<IntGraphType>() { Name = "id" }), resolve: d => { var id = d.Arguments["id"].GetInt(0, false); return bll.GetModel(id); ; }); //查询-列表 Field<ListGraphType<MStudentType>>("students", resolve: d => { return bll.GetStudents(); }); } } } public class StudentMutation : ObjectGraphType { public StudentMutation(BStudent bll) { Field<MResultType>("update", arguments: new QueryArguments( new QueryArgument<IntGraphType> { Name = "id" }, new QueryArgument<StringGraphType> { 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
/// <summary> /// graphql demo 接口 /// </summary> /// <returns></returns> [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工具的接入
//调整以下 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(<GraphiQL fetcher={graphQLFetcher} />, document.getElementById('app'));