GraphQL in ASP.NET Core

一、GraphQL简介

1.什么是GraphQL

       GraphQL是一种用于API的查询语言;它也是一个用来执行查询的服务器端运行时,通过您为您的数据定义的类型系统查进行查询的。

        GraphQL与数据库、存储技术和开发语言、框架无关。

        GraphQL的服务也不限定使用的传输技术,但是通常都是通过HTTP(S)来传输。

       

        

 

 

       查询是可以嵌套的,一次请求,获得多个类型的数据,无需继续钻取数据;客服端不会收到多余的数据。

       每当对GraphQL服务器进行查询的时候,都会使用类型系统进行验证;在Schema里定义类型,如下:
        

         GraphQL通常被称作是   声明式数据获取语言。

2.设计原则

      层次结构性;

     以产品为中心;

     强类型;

     客户端定制查询;

     内省;

3.GraphQL历史

      源自Facebook     2012年Facebook开始开发    2015年开源

 

4.对比Rest

    GraphQL指定查询,精确获取;Rest过渡获取。

     Rest获取不充分;GraphQL可以嵌套查询,一次性获取结果。

      

   通常,可以使用GraphQL管理Rest端点

 

 

 

 5.谁在使用GraphQL

 

 

 二、图论(Graph Theory)

       图论就是研究图的,图可以用来表示一组关联的对象;也可以把图看成是一个包含数据点和连接的对象。例如:人际关系图、家谱、公交线路图。

      1.无向图

      

 

      2.有向图

      

 

    3.树

    

 

 三、查询和修改

1、工具GitHub GraplQL API使用

    访问地址:https://developer.github.com/v4/explorer/

    

 

 

    首先需要登录,登录之后才可以使用。

    登录后简单使用

    

 

 

 

 

2、查询

     GraphQL与SQL对比:SQL查询数据库,GraphQL查询API;SQL的数据存在数据表里,GraphQL的数据可以存在任何地方;SQL使用Select查询数据,GraphQL使用Query;SQL使用Insert、Update、Delete来修改数据,GraphQL使用Mutation修改数据;

      •GraphQL的请求

      GraphQL查询的内容通过HTTP POST 的body发送给GraphQL端点。查询就是从API获取数据,通过字段来请求查询的数据,这些字段和查询结果的JSON响应的字段对应。

      成功查询的JSON结果里包含一个data字段,不成功的查询里包含一个errors字段,里面有具体的错误信息json响应结果可同时包含data和errors字段。

    1) Query是GraphQL的一个类型,叫做根类型

      

 

     

 

    2)片段Fragments:可以复用的选择集

    

 

   3)联合类型Union Type:如果你想返回不止一种类型

      

 

 

   4)接口interface

       

3、修改(mutation)

     

 

四、Schema和Types

1.Schema是什么

    GraphQL会改变你进行设计的过程。使用Rest的时候,可以把你的API看做是一组Rest端点;而在GraphQL里你把你的API看作一组类型,为你暴露API定义的这组数据类型就叫做Schema。

2.设计Schema

    Schema First,使前后端团队在数据类型上保持一致;

   GraphQL使用SDL(Schema Definition Language)语言来定义Schema,GraphQL的Schema就是定义可用类型的文本文档,它被客户端和服务器端用来验证GraphQL请求。

3.类型定义

   

 

 

    叹号表示不能为null

4.一对一连接

   图论里,两个对象之间的连接叫做边,而由一个对象接连到另外一个对象的连接就是一对一连接。

   

 

 

 5.一对多连接

    要尽量保持GraphQL服务的无向性,也就是说可以从图的任何一个顶点开始遍历。

   

 

 

    

 

 

   6.多对多连接

     需要在双方的类型里都添加LIst字段,一个多对多连接由两个一对多连接组成,创建多对多连接是,有时需要保存关系本身,这时就需要通过类型,比如用户和角色。

    

五、使用ASP.Net Core 构建GraphQL

    我的项目结构如下:

     

 

 

 首先我们定义Models,例如:

public class Movie
    {
        public int id { get; set; }

        public string Name { get; set; }

        public  DateTime ReleaseDate { get; set; }

        public string Company { get; set; }

        public int ActorId { get; set; }

        public MovieRating MovieRating { get; set; }
    }


  public  class Actor
    {
        public int id { get; set; }

        public string name { get; set; }
    }

   [Flags]
   public enum MovieRating
    {
        Untrate=0,
        G=1,
        PG=2,
        PG13=3,
        R=4,
        NC17=5
    }

 

  再定义接口和现实

   

 public interface IMovieService
    {
        Task<Movie> GetByIdAsync(int id);

        Task<IEnumerable<Movie>> GetAsync();

        Task<Movie> CreateAsync(Movie movie);
    }


 public class MovieService : IMovieService
    {
        private readonly IList<Movie> _movies;

        public MovieService()
        {
            _movies = new List<Movie>
            {
                new Movie
                {
                     id=1,
                     Name="ZYY1",
                     ActorId=1,
                     Company="kindstar",
                     MovieRating=MovieRating.PG,
                     ReleaseDate=new DateTime(2020,1,2)
                }
                ,
                 new Movie
                {
                     id=1,
                     Name="ZYY2",
                     ActorId=2,
                     Company="kindstar",
                     MovieRating=MovieRating.PG13,
                     ReleaseDate=new DateTime(2020,1,3)
                }
                 , new Movie
                {
                     id=1,
                     Name="ZYY3",
                     ActorId=3,
                     Company="kindstar",
                     MovieRating=MovieRating.G,
                     ReleaseDate=new DateTime(2020,1,4)
                },
                  new Movie
                {
                     id=1,
                     Name="ZYY4",
                     ActorId=4,
                     Company="kindstar",
                     MovieRating=MovieRating.PG,
                     ReleaseDate=new DateTime(2020,1,5)
                },
                   new Movie
                {
                     id=1,
                     Name="ZYY5",
                     ActorId=5,
                     Company="kindstar",
                     MovieRating=MovieRating.Untrate,
                     ReleaseDate=new DateTime(2020,1,2)
                }
            };
        }
        public Task<Movie> CreateAsync(Movie movie)
        {
            _movies.Add(movie);
            return Task.FromResult(movie);
        }

        public Task<IEnumerable<Movie>> GetAsync()
        {
            return Task.FromResult(_movies.AsEnumerable());
        }

        public Task<Movie> GetByIdAsync(int id)
        {
            var movie = Task.FromResult(_movies.SingleOrDefault(x => x.id == id));
            if(movie==null)
            {
                throw new AggregateException(String.Format("ID {0}不正确",id));
            }
            return movie;
        }
    }

 

   之后,我们要去Schema里面定义Type、Schema和Mutation,例子如下:

public class MovieType:ObjectGraphType<Movie>
    {
        public MovieType(IActorService actorService)
        {
            Name = "Movie";
            Description = "";

            Field(x=>x.id);
           
            Field(x => x.Name);
           
            Field(x => x.Company);
            Field(x => x.ReleaseDate);

            Field(x => x.ActorId);
            Field<ActorType>("Actor",resolve: context=> actorService.GetByIdAsync(context.Source.ActorId));

            //Field(x => x.MovieRating);
            Field<MovieRatingEnum>("movieRatings", resolve: context => context.Source.MovieRating);
            Field<StringGraphType>("customString", resolve: context => "1234");

        }
    }

 

public  class MoviesQuery: ObjectGraphType
    {
        public MoviesQuery(IMovieService movieSevice)
        {
            Name = "Query";

            Field<ListGraphType<MovieType>>("movies",resolve:context=> movieSevice.GetAsync());

        }
    }

 

   public class MoviesMutation : ObjectGraphType
    {
        public MoviesMutation(IMovieService movieService)
        {

            Name = "Mutation";

            FieldAsync<MovieType>(
                "createMovie",
                arguments: new QueryArguments(new QueryArgument<NonNullGraphType<MovieInputType>> { Name = "movie" }),
                resolve:async context =>
                { 
                    var movieinput = context.GetArgument<MovieInput>("movie");

                    var movies = await movieService.GetAsync();
                    var maxid = movies.Select(x=>x.id).Max();

                    var movie = new Movie
                    {
                        id = ++maxid,
                        Name = movieinput.Name,
                        Company = movieinput.Company,
                        ActorId=movieinput.ActorId,
                        MovieRating=movieinput.MovieRating,
                        ReleaseDate=movieinput.ReleaseDate
                    };
                    var result = await movieService.CreateAsync(movie);
                    return result;
                });
        }

    }

 

  在项目中,我们需要引用如下包:

dotnet add package GraphQL

 

dotnet add package GraphQL.Server.Transports.WebSockets

 

dotnet add package GraphQL.Server.Transports.AspNetCore

 

 现在去Startup中注入:

public void ConfigureServices(IServiceCollection services)
        {
            services.AddSingleton<IMovieService, MovieService>();
            services.AddSingleton<IActorService, ActorService>();

            services.AddSingleton<MovieType>();
            services.AddSingleton<ActorType>();
            services.AddSingleton<MovieRatingEnum>();
            services.AddSingleton<MoviesQuery>();
            services.AddSingleton<MoviesSchema>();

            services.AddSingleton<MovieInputType>();
            services.AddSingleton<MoviesMutation>();

            services.AddSingleton<IDependencyResolver>(s => new FuncDependencyResolver(s.GetRequiredService));

            services.AddGraphQL(options =>
            {
                options.EnableMetrics = true;
                options.ExposeExceptions = true;

            })
             .AddWebSockets()
             .AddDataLoader();

            services.Configure<KestrelServerOptions>(options =>
            {
                options.AllowSynchronousIO = true;
            });


        }

 

    注意,在.Net Core3.0中要加入红色字体部分,否则会报错:Synchronous operations are disallowed. Call FlushAsync or set AllowSynchronousIO to true instead

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            app.UseWebSockets();

            app.UseGraphQLWebSockets<MoviesSchema>("/graphql");

            app.UseGraphQL<MoviesSchema>("/graphql");

            // use graphql-playground middleware at default url /ui/playground
            app.UseGraphQLPlayground(new GraphQLPlaygroundOptions());

        }

 

红色部分是加入访问的工具,有4个可以选择,如下:

  // use graphiQL middleware at default url /graphiql
    app.UseGraphiQLServer(new GraphiQLOptions());

    // use graphql-playground middleware at default url /ui/playground
    app.UseGraphQLPlayground(new GraphQLPlaygroundOptions());

    // use altair middleware at default url /ui/altair
    app.UseGraphQLAltair(new GraphQLAltairOptions());
    
    // use voyager middleware at default url /ui/voyager
    app.UseGraphQLVoyager(new GraphQLVoyagerOptions());

 

运行后测试如下:

  

 

 参考地址:https://github.com/graphql-dotnet/server

 

posted @ 2020-03-13 16:06  圆圆酥  阅读(405)  评论(0编辑  收藏  举报