zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    Nuget 多平台多目标快速自动打包
    .Net Core 环境下构建强大且易用的规则引擎
    .Net 4.X 提前用上 .Net Core 的配置模式以及热重载配置
    [搬运] DotNetAnywhere:可供选择的 .NET 运行时
    [搬运] .NET Core 2.1中改进的堆栈信息
    [开源]OSharpNS 步步为营系列
    [开源]OSharpNS 步步为营系列
    [开源]OSharpNS 步步为营系列
    [开源]OSharpNS 步步为营系列
    [开源]OSharpNS 步步为营系列
  • 原文地址:https://www.cnblogs.com/zhangyunyun/p/12469205.html
Copyright © 2011-2022 走看看