了解如何在.Net Core和C#中使用GraphQL
GraphQL是由Facebook创建的这项技术,它使前端能够与后端协商所需的数据。如果您愿意,它还可以使API的构建器将来自不同API的数据拼接在一起。这是一项非常酷的技术,它不仅适用于JavaScript,您绝对可以将它用于.Net中的下一个项目。
在本文中,我们将介绍:
- 为什么,我们为什么要这种技术来构建API
- 什么,它包含的部分是什么
- 演示,让我们构建一个API,并学习如何使用我们的数据源
资源
-
GraphQL.org
这是GraphQL组织的网站。它包含有关构建GraphQL的原因,存在的类型等的大量信息。 -
NuGet包graphql-dotnet
这是最流行的NuGet包。它包含一个README页面,可以帮助您入门,还可以演示不同类型的应用程序,例如MVC。 -
从VS Code中的.Net Core开始
这显示了如何在VS Code中开始使用.Net Core。 -
我在.Net Core和VS Code上写的入门文章
我为您撰写了一系列对.Net Core感到好奇的文章。它展示了如何构建不同类型的项目,运行测试等。它甚至涵盖了如何构建无服务器API。
- 如何在JavaScript中构建和使用GraphQL API如果您想了解JavaScript中的工作方式,请查看我编写的这些文章。
为什么,为什么我们首先需要它。 REST API有什么问题?
GraphQL允许内容协商,这意味着您只有一个端点。它还允许您准确查询所需的字段。在后端,您还可以从不同的数据源获取数据,因此对于前端开发人员和后端开发人员来说,确实有充分的理由感到兴奋。
什么,GraphQL存在哪些部分
GraphQL由模式定义组成。您可以在名为GQL,GraphQL查询语言的东西中定义该架构,但您也可以修饰类以响应某些资源(在以后的文章中更多关于那个)。
除了模式之外,还有一个称为解析器的中心概念。解析器只是一个知道如何处理传入查询的函数。解析器映射到某个资源。
然后你有一个名为GraphiQL的可视化环境,允许你运行查询。大多数GraphQL实现都带有某种形式的可视化环境。
如何查询
当你查询时,GraphQL看起来有点特别,但它很简单。要查询您要输入的资源:
{ resource }
然而,这还不够。您还需要指定所需的列,如下所示:
{ resource { column, column2 } }
要使用参数进行查询,您可以像这样输入:
{ users(id:1) { name, created } }
最终结果始终是与您的查询匹配的JSON响应,因此如果我们采用上述查询,我们会得到一些看起来像这样的东西:
{ "data": { "users": ({ "name" : "chris", "created": "2018-01-01" }) } }
演示 – 让我们构建一个API。
我们需要将一些GraphQL理论与代码混合在一起。因此,我们将介绍一个概念,然后显示它的代码。
建立
我们需要做以下事情
- 创建解决方案
- 创建一个控制台应用
- 安装GraphQL NuGet包
创建解决方案
让我们首先创建一个解决方案目录,如下所示:
mkdir demo cd demo
接下来,让我们创建实际的解决方案文件:
dotnet new sln
创建控制台应用程序
让我们像这样创建一个控制台项目:
dotnet new console -o App
然后导航到它
cd App
添加我们的GraphQL NuGet库
接下来,让我们添加我们的GraphQL NuGet包
dotnet add package GraphQL
你好GraphQL
现在我们准备添加代码了
// Program.cs using System; using GraphQL; using GraphQL.Types; namespace App { class Program { static void Main(string() args) { Console.WriteLine("Hello World!"); var schema = Schema.For(@" type Query { hello: String } "); var root = new { Hello = "Hello World!" }; var json = schema.Execute(_ => { _.Query = "{ hello }"; _.Root = root; }); Console.WriteLine(json); } } }
上面的代码中有三个有趣的部分:
- 声明我们的架构
- 定义我们的解析器
- 将我们的查询排除在API之外
声明我们的架构
我们输入的字符串 Schema.For
包含一些名为GQL或GraphQL查询语言的东西。它通常定义三件事:
- 查询,这是我们可以查询的内容
- 类型,我们还没有任何类型,但我们稍后会在文章中介绍。
- 突变,我们可以称之为语义上意味着我们会改变一些东西
让我们特别关注我们设置架构的部分:
var schema = Schema.For(@" type Query { hello: String } ");
现在我们只有 type Query
它说的是我们可以查询 hello
并且响应是字符串类型, hello: string
。
解决我们的查询
架构只是这个难题的一部分。另一部分是解析器代码。这段代码实际上是处理传入请求的。在我们的例子中,解析器代码如下所示:
var root = new { Hello = "Hello World!" };
正如我们在上面看到的,它会在我们的查询中映射一些内容 hello
并说,如果用户要求 hello
,然后我们将回答 Hello World
。
执行查询
在下面的代码中,我们执行查询 { hello }
通过将其分配给财产 _.Query
在我们提供的lambda表达式中 schema.Execute()
。
var json = schema.Execute(_ => { _.Query = "{ hello }"; _.Root = root; });
然后我们的查询结果被分配给 json
我们可以使用以下方法轻松将其打印到终端:
Console.WriteLine(json);
架构优先
这是一种不同的方法,我们将使用类并装饰它们,这个想法是类将包含在我们进行查询时将用作解析器的方法。
为此,我们需要执行以下操作:
-
更新我们的架构,我们需要一个新的自定义类型,我们需要在它中公开它
Query
-
创建一些我们需要支持Type,Query和内存数据库的类
架构更新
到目前为止,我们的架构没有类型。让我们通过添加Jedi类型来改变它,让我们也将它作为我们可以查询的内容公开,如下所示:
Schema.For(@" type Jedi { name: String, side: String } type Query { hello: String, jedis: (Jedi) } ", _ => { _.Types.Include<Query>(); });
上面我们补充说 Jedi
作为一种写作类型 type Jedi
并在其中定义其属性 {}
。然后我们添加 jedis
到了 Query
并说它是类型的 (Jedi)
这意味着它是一个数组 Jedi
。最后我们给了我们 Schema.For()
第二个论点:
_.Types.Include<Query>();
这意味着我们指出了一个班级 Query
将处理所有传入的请求。我们还没有那个价格,所以让我们创建它。
创建支持类
首先我们需要上课 Query
。它现在有责任处理内部的任何事情 Query
在我们的架构中,这意味着它需要处理 hello
和 jedis
。我们来看看是什么 Query
可以看起来像:
public class Query { (GraphQLMetadata("jedis")) public IEnumerable<Jedi> GetJedis() { return StarWarsDB.GetJedis(); } (GraphQLMetadata("hello")) public string GetHello() { return "Hello Query class"; } }
这里我们定义两种方法 GetJedis()
和 GetHello()
。注意我们如何使用装饰器 GraphQLMetadata
在每个方法上映射我们的哪个属性 Query
他们将处理。我们也看到我们打电话给一个班级 StarWarsDB
所以我们需要创建下一个:
public static IEnumerable<Jedi> GetJedis() { return new List<Jedi>() { new Jedi(){ Name ="Luke", Side="Light"}, new Jedi(){ Name ="Yoda", Side="Light"}, new Jedi(){ Name ="Darth Vader", Side="Dark"} }; }
定义要查询的内容
让我们定义用于查询GraphQL API的查询:
{ jedis { name, side } }
我们上面说的是我们想要查询 jedis
我们想要列 name
和 side
。将其与SQL表达式进行比较,我们将改为输入:
SELECT name, side FROM jedis;
让我们用我们的查询更新代码,如下所示:
var json = schema.Execute(_ => { _.Query = "{ jedis { name, side } }"; }); Console.WriteLine(json);
结果是:
这似乎工作正常,好吧:)
使用参数
现在我们已经做了很多工作,但我们需要能够处理参数,有时我们只想要一条记录,所以我们需要根据一个密钥过滤更大的集合。为了实现这一目标,我们需要:
-
更新我们的Schema以支持带参数的查询
-
在我们的Query类中创建一个能够解析参数的方法
-
验证一切正常
更新我们的架构
首先我们需要更新我们的模式,所以我们支持一个带参数的查询,如下所示:
Schema.For(@" type Jedi { name: String, side: String, id: ID } type Query { hello: String, jedis: (Jedi), jedi(id: ID): Jedi } ", _ => { _.Types.Include<Query>(); });
我们实际上正在做两件事。我们正在增加这个领域 id
到了 Jedi
类型。我们也在添加这一行 Query
:
jedi(id: ID): Jedi
更新我们的代码
我们的绝地课没有 Id
字段,所以我们需要添加,如下:
public class Jedi { public int Id { get; set; } public string Name { get; set; } public string Side { get; set; } }
接下来我们需要在查询类中添加一个方法,如下所示:
(GraphQLMetadata("jedi")) public Jedi GetJedi(int id) { return StarWarsDB.GetJedis().SingleOrDefault(j => j.Id == id); }
请注意上面我们只需要命名匹配 id
作为输入参数。代码本身只是一个 SingleOrDefault
linq查询,它给我们一个条目返回。
更新查询
让我们尝试查询这个新资源,如下所示:
{ jedi(id: 1) { name } }
结果:
工作!!! 🙂
摘要
我们已经涵盖了很多方面。我们已经介绍了GQL,GraphQL查询语言。此外,我们还学习了如何在模式中定义资源,自定义类型以及如何解决这些问题。关于GraphQL还有很多东西需要学习,但本文已经足够长了。我希望这是一个有趣的第一眼看。在下一部分中,我们将介绍如何构建无服务器API并以这种方式利用GraphQL并将其部署到云。