冠军

导航

GraphQL Part II: 中间件

GraphQL Part II: 中间件

 如果您熟悉 ASP.NET Core 的中间件,您可能注意到在我们上一篇博客中我们已经拥有了一个中间件。在初始的空白应用中,中间件的职责是返回 hello World 响应。后来, 我们用我们的自定义代码替换了它, 以便它可以响应一些静态 GraphQL 查询的结果。

 中间件是一种可以装配到应用处理管线中的软件,以便处理请求和响应。每个组件包括:

  • 选择是否将请求传递给管线中的下一个组件
  • 可以在管线调用下一个组件之前或者之后执行任务

事实上,中间件是一个代理,或者更精确地说,他是一个请求代理。如名字所提示,它处理传入的请求并决定是否传递到管线中的下一个中间件。在我们的案例中,我们使用 IApplicationBuilder 的 run() 扩展方法来配置请求代理。在 3 个扩展方法之间 ( use, run, map ),Run() 方法在请求管线中终止了进一步的请求处理。

我们中间件中的代码非常简单,仅仅返回硬编码的静态查询,但是,在真实场景下,query 应该是动态的,我们必须从传入的请求中获取它。

每个请求代理接受一个 HttpContet 对象。如果 query 是通过 HTTP 的 Post 方式提交,您可以使用如下代码读取请求体。

string body;  
using (var streamReader = new StreamReader(httpContext.Request.Body))  
{
    body = await streamReader.ReadToEndAsync();
}

 

 在读取其内容之前做校验工作,就不会带来危害。所以,让我们放置一个 if 来检查两件事:

  • 它是 Post 请求吗?
  • 它来自特定的 URL 地址吗?

我们的代码做如下修改:

if(context.Request.Path.StartsWithSegments("/api/graphql") && 
string.Equals(context.Request.Method, "POST", StringComparison.OrdinalIgnoreCase)) { string body; using (var streamReader = new StreamReader(context.Request.Body)) { body = await streamReader.ReadToEndAsync(); }
......

 

请求体重可以包含大量字段,但是,我们可以说传入的 GraphQL 查询在名为 query 的字段内。所以,我们可以解析 body 的内容到一个包含 Query 属性的复杂类型示例中。

复杂类型如下所示:

public class GraphQLRequest
{
    public string Query { get; set; }
}

 

下一步要做的就是反序列化 body 内容到 GraphQLRequest 对象示例中,使用 Json.Net 的 JsonConvert.DeserializeObject 并替换前面硬编码的内容。

var request = JsonConvert.DeserializeObject<GraphQLRequest>(body);


var result = await new DocumentExecuter().ExecuteAsync(doc =>
{
    doc.Schema = schema;
    doc.Query = request.Query;
}).ConfigureAwait(false);

 

在所有的修改之后,在 Startup.cs 中的 Run 方法如下所示:

app.Run(async (context) =>
{
    if (context.Request.Path.StartsWithSegments("/api/graphql")
   && string.Equals(context.Request.Method, "POST", StringComparison.OrdinalIgnoreCase))
    {
        string body;
        using (var streamReader = new StreamReader(context.Request.Body))
        {
            body = await streamReader.ReadToEndAsync();

            var request = JsonConvert.DeserializeObject<GraphQLRequest>(body);
            var schema = new Schema { Query = new HelloWorldQuery() };

            var result = await new DocumentExecuter().ExecuteAsync(doc =>
            {
                doc.Schema = schema;
                doc.Query = request.Query;
            }).ConfigureAwait(false);

            var json = new DocumentWriter(indent: true).Write(result);
            await context.Response.WriteAsync(json);
        }
    }
});

 

现在,可以使用任何客户端 ( Postman 或者 Insomnia ) 发送一个包含 query 字段的 POST 请求.

我们几乎完成了工作,但是您可以看到大量的 new 代码创建对象,例如:new DocumentExecuter(),new Schema(), new DocumentWriter() 等等,下一节,我们将使用 ASP.NET Core 内置的依赖注入系统注入它们。

 

上一篇:GraphQL Part I: hello, world.

下一篇:GraphQL Part III: 依赖注入

参考资料

 

posted on 2020-03-28 17:56  冠军  阅读(378)  评论(0编辑  收藏  举报