GraphQL:面對複雜類型

GraphQL 既是一種用於 API 的查詢語言也是一個滿足你數據查詢的運行時。GraphQL 對你的 API 中的數據提供了一套易於理解的完整描述,使得客戶端能夠準確地獲得它需要的數據,而且沒有任何冗餘,也讓 API 更容易地隨着時間推移而演進,還能用於構建強大的開發者工具。

                                   ——出自 https://graphql.cn

上一篇博文中,我們返回值是一個字符串,對於大多數情況,我們更多的是返回實體類的json格式。

第一版

using HotChocolate;
using HotChocolate.Data;
using HotChocolate.Execution;
using HotChocolate.Types;
using System;
using System.Collections.Generic;




namespace GraphQLBase002
{
    class Program
    {
        static void Main(string[] args)
       {         
            FirstVersion.Run();       
        }
    }
   //實體類
    public class Student
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public int Age { get; set; }
    }


    #region FirstVersion
    public class FirstVersion
    {
        public static void Run()
{
            var schema = SchemaBuilder.New()
                .AddQueryType<QueryType>()
                .Create();
            var executor = schema.MakeExecutable();
            //回爲返回是字符串,所以用定義的Resolver name來查詢
            Console.WriteLine(executor.Execute("{ students }").ToJson());
        }


        public class Query
        {
            public IList<Student> GetStudents()
            {
                return new List<Student>() {
                    new Student {
                        Id = 100,
                        Name = "ABCD",
                        Age=20
                    },
                     new Student {
                        Id = 101,
                        Name = "EFGH",
                        Age=19
                    }
                };
            }
        }


        public class QueryType : ObjectType<Query>
        {
            protected override void Configure(IObjectTypeDescriptor<Query> descriptor)
{
                //定義了有students來請求GetStudents方法,返回的類型是StringType,所以在Resolver中會把實體轉成Json
                descriptor.Field<Query>(t => t.GetStudents()).Name("students").Type<NonNullType<StringType>>().Resolver(ctx =>
               {
                   var result = ctx.Parent<Query>().GetStudents();
                   return Newtonsoft.Json.JsonConvert.SerializeObject(result);
               });
            }
        }
    }
    #endregion

爲了返回一個json,用Resolver來獲取GetStudents,並把實例親手轉成json返回,因爲是字符串,所以這個Field的Type是StringType。

運行結果,看起來是個json,不,準確說是一個json格式的字符串,其實從我們定義Resolver來說就非常清楚了;這並不是我們想要的。

第二版

    #region SecondVersion
    public class SecondVersion
    {
        public static void Run()
{
            var schema = SchemaBuilder.New()
                .AddQueryType<QueryType>()
                .Create();
            var executor = schema.MakeExecutable();


            Console.WriteLine(executor.Execute("{ student {id name} }").ToJson());
            Console.WriteLine(executor.Execute("{ students {id name} }").ToJson());
        }
        public class Query
        {


            public Student GetStudent()
{
                return new Student
                {
                    Id = 1,
                    Name = "AAAAA",
                    Age = 19


                };
            }


            public List<Student> GetStudents()
            {
                return new List<Student>{
                    new Student
                    {
                        Id = 100,
                        Name = "ABCD",
                        Age = 19
                    },
                    new Student
                    {
                        Id = 101,
                        Name = "EFGH",
                        Age = 20
                    }
                };
            }
        }


        public class StudentType : ObjectType<Student>
        {
            protected override void Configure(IObjectTypeDescriptor<Student> descriptor)
{
            }
        }


        public class QueryType : ObjectType<Query>
        {
            protected override void Configure(IObjectTypeDescriptor<Query> descriptor)
{
                descriptor.Field(t => t.GetStudent()).Type<NonNullType<StudentType>>().Name("student");
                descriptor.Field(t => t.GetStudents()).Type<ListType<NonNullType<StudentType>>>().Name("students");
            }
        }
    }
    #endregion

這次我們爲了不再是json格式字符串,在代碼中定義了StudentType這個的類型,告訴系統Student不是一個簡單類型,但Student內的屬性,都是簡單類型,所以在Configure中沒有作任何處理(如果Student中有自定義複雜類型的屬性,還得進一步定義這個類型,並在Configure中處理),在QueryType中,處理了Query中的兩個方法的類型定義和重命名。

運行結果如下,對,這就是我們要的結果;但總覺得爲了實現返回json,我們的代價是不是有點大?

第三版

#region ThreeVersion
    public class ThreeVersion
    {
        public static void Run()
        {
            var schema = SchemaBuilder.New()
                .AddProjections()
                .AddQueryType<Query>()
                .Create();
            var executor = schema.MakeExecutable();


            Console.WriteLine(executor.Execute("{ student{id name age} }").ToJson());
            Console.WriteLine(executor.Execute("{ students{id name age} }").ToJson());
        }
        public class Query
        {
            [UseProjection]            
            public Student GetStudent()
            {
                return new Student
                {
                    Id = 1,
                    Name = "AAAAA",
                    Age = 19


                };
            }
            [UseProjection]
            public List<Student> GetStudents()
            {
                return new List<Student>{
                    new Student
                    {
                        Id = 100,
                        Name = "ABCD",
                        Age = 19
                    },
                    new Student
                    {
                        Id = 101,
                        Name = "EFGH",
                        Age = 20
                    }
                };
            }
        }
    }
    #endregion

這一版我們借雞下蛋,用UseProjection來替代了我們定義的類型,連QueryType也消失了,這樣的代碼纔是我們想要的,讓我們更關注業務的邏輯,而不是關注爲了GraphQL,而做很多技術配合工作;其實我們從第二版看定義的類型StudentType,QueryType,也知道這些類型是非常規律性的,是可以通過代碼手段替代的,那就是UseProjection。

運行結果與版本二一樣。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章