本文章是介紹和記錄如何創建GraphQL項目,以及如何使用GraphQL進行數據的相關操作。項目參照GraphQL .Net 的官方文檔進行實踐 一、項目結構: 為了更好的和原有的項目結合在一起,儘可能減少對原項目的修改。我對項目結構做瞭如下分層。 二、項目結構分層說明 Contracts層: 項目 ...
本文章是介紹和記錄如何創建GraphQL項目,以及如何使用GraphQL進行數據的相關操作。項目參照GraphQL .Net 的官方文檔進行實踐
一、項目結構:
為了更好的和原有的項目結合在一起,儘可能減少對原項目的修改。我對項目結構做瞭如下分層。
二、項目結構分層說明
Contracts層: 項目的介面層,重點存放項目的一些介面。和原項目的分層結構的Contracts一致
Entities層: 實體模型層,存放實體模型。與原有項目的分層結構Entites層一致
GraphQLDemo: 是使用Console控制台應用程式對GraphQL的調用實例
GraphQLs: 使用GraphQL 的模型定義和查詢、變更等操作的定義
Services: 提供服務的具體實現層,和原有項目分層中的Services 層一致
Tests: 使用Unit Test 測試調用GraphQL
在這裡重點關註 標紅的部分的介紹
三、GraphQLs項目介紹:
GraphQLs重點是存儲項目的GraphQL操作相關的內容
1.在項目解決方案中,新建程式集,命名為GraphQLs
2. 安裝Graphql
NuGet 搜索 GraphQL
3.創建GraphQL 的相關概念
GraphQL有兩種方式創建Schema,
-
- 一種是使用Schema First,也就是使用GraphQL Schema Language創建Schema. 可以對比EntityFramework的DB First
- 一種是使用Graph Type定義Schema,可以對比EntityFramework 的Code First
在這裡適用Code First定義數據模型,可以與原有的數據服務應用一起使用。可分為以下步驟:
1)定義數據模型:
假設原有的數據模型Book的結構是這樣的:
public class User { public int Id { get; set; } public string Name { get; set; } public int Age { get; set; } public string Gender { get; set; } }
那麼定義對應的GraphQL的數據模型可以是這樣的:
public class UserType:ObjectGraphType<User>// 繼承自ObjectGraphType,並傳遞範型User { public UserType()// 在構造函數中,對屬性作影射 { Name = "User"; Field(x => x.Id); Field(x => x.Name); Field(x => x.Age); Field(x => x.Gender); } }
2)定義操作模型:
GraphQL的操作分為: Query(Select), Mutation(Create,Update,Delete),Subscription(訂閱)
- 定義Query操作
public class Query : ObjectGraphType// 定義Query { private IWrapper wrapper = new Wrapper(); IEnumerable<User> users = null; public Query() { Field<ListGraphType<UserType>>(//在構造函數中定義查詢操作 name: "users", //註意這個名字,後邊查詢的時候需要對應 arguments: new QueryArguments //定義查詢參數 { new QueryArgument<StringGraphType> { Name = "name", Description = "The name for the user" }, new QueryArgument<IntGraphType> { Name = "age", Description = "The age for the user" }, new QueryArgument<StringGraphType> { Name = "gender", Description = "The gender for user" } }, resolve: context =>// 定義查詢操作的執行 { var usercontext = context.UserContext;// 獲取上下文,可在此作用戶驗證操作 users = wrapper.User.Find(u => true); var name = context.GetArgument<string>("name"); users = users.Where(u => name == null || u.Name == name); var age = context.GetArgument<int?>("age"); users = users.Where(u => age == null || u.Age == age); var gender = context.GetArgument<string>("gender"); users = users.Where(u => gender == null || u.Gender == gender); return users; });
}
}
- 定義Mutation操作
public class Mutation:ObjectGraphType { private IWrapper wrapper = new Wrapper(); IEnumerable<User> users = null; public Mutation() { Field<UserType>( name: "createUser", arguments: new QueryArguments( new QueryArgument<NonNullGraphType<UserInputType>> { Name = "user" } ), resolve: context => { var user = context.GetArgument<User>("user"); return wrapper.User.Add(user); } ); } }
3. 定義GraphSchema
定義GraphSchema就是定義Schema的Query、Mutation、Subscription操作
public class GraphSchema:Schema { public GraphSchema() { Query = new Query(); Mutation = new Mutation(); } }
4. 附.
為了檢驗查詢、修改操作,這裡定義一個GraphQLQuery來定義操作,並定義一個查詢操作類
public class GraphQLQuery { public string OperationName { get; set; } public string NamedQuery { get; set; } public string Query { get; set; } public object UserContext { get; set; } public JObject Variables { get; set; } }
public class ActionExecute { private IDocumentExecuter executer; private IDocumentWriter writer; private ISchema schema; public ActionExecute() { executer = new DocumentExecuter(); writer = new DocumentWriter(); schema = new GraphSchema(); } public async Task<ExecutionResult> ExecuteAction(GraphQLQuery query) { var result = await executer.ExecuteAsync(_ => { _.Schema = schema; _.Query = query.Query; _.Inputs = query.Variables.ToInputs();// 查詢變數的輸入 _.OperationName = query.OperationName;// 操作名稱 _.UserContext = query.UserContext;// 添加用戶上下文對象 _.ValidationRules = DocumentValidator.CoreRules(); // 添加自定義查詢驗證 邏輯 _.ExposeExceptions = true;// 是否追蹤錯誤 _.FieldMiddleware.Use<ErrorHandlerMiddleware>(); // 使用中間件 _.EnableMetrics = true;// 是否使用查詢度量 _.ComplexityConfiguration = new ComplexityConfiguration // 防止惡意查詢 { MaxComplexity = 12, MaxDepth = 15 // 允許查詢總最大嵌套數 }; }); return result; } public async Task<string> Execute(GraphQLQuery query) { var result = await ExecuteAction(query).ConfigureAwait(false); var json = await writer.WriteToStringAsync(result); return json; } }
四、 測試和檢驗
一切準備就緒,下邊對創建的GraphQL進行測試
- 查詢測試:
public class QueryTest { private ActionExecute execute = new ActionExecute(); [Fact] public void TestMethod1() { Assert.True(1 == 1); } [Theory] [InlineData(16, "Male")] [InlineData(18, "FeMale")] public async void QueryUsers(int age, string gender) { var queryStr = @"{users(age:" + age + ",gender:" + "\"" + gender + "\"" + "){id name gender age}}"; var result = await execute.ExecuteAction(new GraphQLQuery { Query = queryStr,UserContext= "Add Role" }); var data = result.Data; Assert.Null(result.Errors?.Count); } }
為了檢驗GraphQL的查詢優越性,你可以修改一下queryStr=@"{users{id name gender age}}"; 或queryStr=@"{users{gender age}}";queryStr=@"{users{ name age}}";註意這裡的@和{}只是C# 對字元串操作的一種方式。
發現了什麼?
如果我們在前端(Web、微信小程式、手機APP),在web端,作為後臺管理系統,我可能需要獲取用戶的所有信息,那麼我可能需要使用queryStr=@"{users{id name gender age}}"。在微信小程式端,我只要根據用戶的id查詢用戶名字就可以了,那麼我只用變動查詢語句:queryStr=@"{users(id){ name}}";
意味著什麼?
意味著我們只需要提供一個API介面,該埠接受傳遞的查詢字元串就可以了。所有的實體都可以只用這一個介面了。想查詢什麼,由前端決定了,再也不需要追著後端介面開發工程師要數據了。我想這樣以來,前端和後端只需要一個介面溝通,會比REST API來的更方便了。
2.變更測試:
public class MutationTest { private ActionExecute execute = new ActionExecute(); [Theory] [InlineData(16, "Test1")] [InlineData(18, "Test2")] public async void CreateUser(int age, string name) { var queryStr = @"{query: mutation ($user: UserInput!){createUser(user:$user){id name age}},variables:{user:{name: " + name + @",age:" + age + @"}}}"; var query = new GraphQLQuery { Query = "mutation ($user: UserInput!){createUser(user:$user){id name age}}", Variables = JObject.Parse("{user:{\"name\": \"" + name + "\",\"age\":" + age + "}}") }; var result = await execute.ExecuteAction(query); Assert.Null(result.Errors.Count); } }
發現了什麼?
同樣的。我們只需要傳遞查詢的參數,傳遞對應的參數Variables 就能完成修改動作。同時,該變更和查詢的操作字元串語句很像,只是多了一個mutation。
五、後續
這篇文章只是介紹了使用控制台和UnitTest測試使用了GraphQL,後續會更新在Asp.Net Core MVC 中使用GraphQL,也可以學習楊旭的文章。很好的博主https://www.cnblogs.com/cgzl/p/9691323.html