众所周知RESTful API是目前最流行的软件架构风格之一,它主要用于客户端和服务器交互类的软件。基于这个风格设计的软件能够更简洁,更有层次,更易于实现缓存等机制。
RESTful的优越性是毋庸置疑的,不过GraphQL也能够做为一种补充,让你的服务既支持RESTful的http调用,也允许客户端经过GraphQL支持的声明式语法调用服务。
本篇文章并不想对比RESTful和GraphQL孰轻孰重,或者那种方式更好,相关比较能够参考GraphQL的前世此生。本文旨在介绍如何在ASP.NET Core应用中引入GraphQL,让你的应用既支持RESTFul,也能支持GraphQL。html
若是说一个Service可以提供一个功能,那么咱们就能够给Service一个输入,从而获得一个输出。
java
若是将若干个Service组合在一块儿造成一个应用程序,那么这个应用程序就能够提供若干个能力,当一个框架分别就输入和输出进行统一的约定和规范时,也就是人们常说的SOAP,RESTful等技术。
git
对于RESTful来讲,输入就是Http request,输出是一个json格式的字符串。而Web应用程序框架在作什么?根据某个输入(request),找到对应的controller, 击中合适的action,同时将Request绑定为action方法的参数,最后将结果格式化为json字符串并输出。
github
GraphQL就是跟Web框架同一级别的技术,只不过输入(input)再也不是Http request,而是GraphQL特有的语法结构,输出仍然为json字符串。
web
既然GraphQL是一种能够代替RESTful的技术,那么你必定很想知道他是怎么作到的。 若是能用一句话总结那就是: GraphQL是一种API资源的查询语言。GraphQL经过下面的三种类型来知足用户的需求:json
咱们都知道用户的请求能够分为两类:Query和Command,Query用于查询资源,调用一次和屡次都不会影响资源的状态,一个简单的查询以下:浏览器
query { hero { id name } }
上面的查询语言能够理解为:查询hero资源的"id"和"name“属性缓存
所谓mutation就是Command,意味着该用户请求可以改变服务端的状态,一个简单的mutation以下:服务器
mutation ($human:HumanInput!) { createHuman(human: $human) { id name } } variables: { "human": { "name": "Boba Fett", "homePlanet": "Kamino" } }
上面的mutation能够理解为建立一个humman对象,输入对象是一个$human变量,最后把建立对象的`”id"和"name"属性查询出来。能够看出mutation通常都要配合一个变量使用,变量须要在"variables"中单独定义。websocket
Subscriptions用于提供相似websocket的功能,GraphQL Server是一个实现了Apollo GraphQL订阅协议的.NET Core服务器. 下面的例子须要同时打开两个浏览器窗口:
Subscription用户订阅聊天消息:
subscription MessageAdded { messageAdded { from { id displayName } content } }
Mutation用户添加聊天内容:
mutation AddMessage($message: MessageInputType!) { addMessage(message: $message) { from { id displayName } content } } variables: { "message": { "content": "Message", "fromId": "1" } }
我在用每个开源框架或者类库时都习惯于先浏览源码,了解整个源码的大概结构和实现。下面的过程以一个简单的查询为例,分析GraphQL的实现原理:
{ query test { user{ age } } }
经过graphQL browser IDE发送请求:
GrpahQL处理的整个过程以下:
curl 'http://localhost:5000/graphql' -H 'Accept-Encoding: gzip, deflate, br' -H 'Content-Type: application/json' -H 'Accept: application/json' -H 'Connection: keep-alive' -H 'DNT: 1' -H 'Origin: http://localhost:5000' --data-binary '{"query":"# Write your query or mutation here\nquery test{\n user{\n age\n }\n}\n"}' --compressed
public class GraphQLRequest { [JsonProperty("query")] public string Query { get; set; } [JsonProperty("variables")] public JObject Variables { get; set; } [JsonProperty("operationName")] public string OperationName { get; set; } public Inputs GetInputs() { return GraphQLRequest.GetInputs(this.Variables); } }
针对上面的例子,实际上只有string Query属性被反序列化为”"# Write your query or mutation here\nquery test{\n user{\n age\n }\n}\n"“
var source = new Source(body); var result = _parser.Parse(source);
Parse后的结果是一个Document类:
public class Document : AbstractNode { public string OriginalQuery { get; set; } public Operations Operations { get; } public Fragments Fragments { get; } }
本例的Query将会被解析为一个Operations,一个Operations将包含若干个有层次结构的Operation,解析Query的目的是为了知道客户端要查询user.Age这个属性。
public async Task<ExecutionResult> ExecuteAsync(ExecutionOptions options) { //1. 打印开始时间 //2. Parse Document //3. 验证Document是不是一个合法的GrapQL语法请求 //4. 在流程的各个阶段执行Listener,用于在不一样的时机切入代码,相似于ASP.NET Core中的Filter //5. 选择合适的执行策略 //6. 执行服务端资源 //7. 输出Response }
以上就是GraphQL在.NET Core中的实现原理分析,下一篇将经过一个hello world级别的例子演示如何让你的ASP.NET应用程序支持GraphQL.