Dotnet api graphql linux: Difference between revisions

From bibbleWiki
Jump to navigation Jump to search
Line 280: Line 280:


==Add Arguments To Query==
==Add Arguments To Query==
===Introduction===
* Add Support to Repository to Get One Item
* Create A Query For Graph QL Type
===Add Support to Repository to Get One Item===
<syntaxhighlight lang="c#">
        public async Task<Product> GetOne(int id)
        {
            return await _dbContext.Products.SingleOrDefaultAsync(p => p.Id == id);
        }
</syntaxhighlight>
===Create A Query For Graph QL Type===
===Create A Query For Graph QL Type===
Add the arguments you want with the name for the argument along with a context to suppport it.
Add the arguments you want with the name for the argument along with a context to suppport it.

Revision as of 03:46, 7 August 2020

Creating a Project

Copy the project from RAID array

Sorry no help here

Add the packages

dotnet add package GraphQL

Create Database

Change the connection string

"CarvedRock": "Server=.;Database=CarvedRock;Trusted_Connection=False;User Id=test;Password=nottherealone"

Update the database

dotnet ef database update

Run the Site

To the site and look at https://localhost:5001/ui/playground

Creating a Schema

Create a Product Graph Type

Create Fields based on Meta Fields within ObjectGraphType

    public class ProductType: ObjectGraphType<Product>
    {
        public ProductType()
        {
            Field(t => t.Id);
            Field(t => t.Name).Description("The name of the product");
            Field(t => t.Description);
        }
    }

Create a Query

Create a Query which looks in the repository (DB) and gets all of the products.

    public class CarvedRockQuery: ObjectGraphType
    {
        public CarvedRockQuery(ProductRepository productRepository)
        {
            Field<ListGraphType<ProductType>>(
                "products", 
                resolve: context => productRepository.GetAll()
            );
        }
    }

Create a Schema for the Carved Rock Query

This holds the queries the schema supports. In our case the CarvedRockQuery created above

    public class CarvedRockSchema: Schema
    {
        public CarvedRockSchema(IDependencyResolver resolver): base(resolver)
        {           
            Query = resolver.Resolve<CarvedRockQuery>();
        }
    }

Configuring ASP .NET Core

In the Startup, Add the dependency resolver to the services, add the Schema and GraphQL configuring options.

        public void ConfigureServices(IServiceCollection services)
        {

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

            services.AddScoped<CarvedRockSchema>();

            services.AddGraphQL(o => { o.ExposeExceptions = false; })
                .AddGraphTypes(ServiceLifetime.Scoped);

Add the GraphQL to the middleware

        public void Configure(
            IApplicationBuilder app, 
            CarvedRockDbContext dbContext)
        {
           app.UseGraphQL<CarvedRockSchema>();
           app.UseGraphQLPlayground(new GraphQLPlaygroundOptions());

Creating a GraphQL API

Adding Scalar Type

  • Create the enumerator
  • Derive a Graph QL Type to hold the Enum
  • Add to Graph QL Type
  • Add the new Graph QL Type to the existing Type

Create the enumerator

    public enum ProductType
    {
        Boots,
        ClimbingGear,
        Kayaks
    }

Derive a Graph QL Type to hold the Enum

    public class ProductTypeEnumType: EnumerationGraphType<Data.ProductType>
    {
        public ProductTypeEnumType()
        {
            Name = "Type";
            Description = "The type of product";
        }
    }

Add the new Graph QL Type to the existing Type

    public class ProductType: ObjectGraphType<Product>
    {
        public ProductType()
        {
            Field(t => t.Id);
...
            Field<ProductTypeEnumType>("Type", "The type of product");
...

Adding Complex Type

Steps Required to Add a Complex Type

  • Create a class
  • Add a Accessor to the DbContext
  • Add the new Repository Class to Startup
  • Add a GraphQL Type
  • Create a Repository Class
  • Add the Graph QL Type to the Product
  • Update the Database

Create the class

    public class ProductReview
    {
        public int Id {get; set;}
        public int ProductId {get; set;}
        public Product Product {get; set;}
        [StringLength(200), Required]
        public string Title {get; set;}
        public string Review {get; set;}
    }

Add a Accessor to the DbContext

    public class CarvedRockDbContext: DbContext
    {
...
        public DbSet<ProductReview> ProductReviews { get; set; }
    }

Add a GraphQL Type

    public class ProductReviewType : ObjectGraphType<ProductReview>
    {
        public ProductReviewType()
        {
            Field(t => t.Id);
            Field(t => t.Title);
            Field(t => t.Review);
        }
    }

Create a Repository Class

    public class ProductReviewRepository
    {
        private readonly CarvedRockDbContext _dbContext;

        public ProductReviewRepository(CarvedRockDbContext dbContext)
        {
            _dbContext = dbContext;
        }

        public async Task<IEnumerable<ProductReview>> GetForProduct(int productId)
        {
            return await _dbContext.ProductReviews.Where(pr => pr.ProductId == productId).ToListAsync();
        }

        public async Task<ILookup<int, ProductReview>> GetForProducts(IEnumerable<int> productIds)
        {
            var reviews = await _dbContext.ProductReviews.Where(pr => productIds.Contains(pr.ProductId)).ToListAsync();
            return reviews.ToLookup(r => r.ProductId);
        }
    }

Add the new Repository Class to Startup

        public void ConfigureServices(IServiceCollection services)
        {
...
            services.AddScoped<ProductRepository>();
            services.AddScoped<ProductReviewRepository>();

Add the Graph QL Type to the Product

    public class ProductType : ObjectGraphType<Product>
    {
        public ProductType(ProductReviewRepository reviewRepository)
        {
            Field(t => t.Id);
            Field(t => t.Name).Description("The name of the product");
...
            Field<ListGraphType<ProductReviewType>> (
                "Reviews",
                resolve : context =>  reviewRepository.GetForProduct(context.Source.Id)
            );

Update the Database

This did not work for me the first time so this might be wrong. Whatever you need to make sure the table exists on the database.

dotnet ef migrations add AddReviews
dotnet ef database update

DataLoader

Introduction

Might be being unfair but this looks the same a creating a view of tables to cache parent /child relationships

  • Add to Starup Services
  • Define a Lookup Function in Repository
  • Inject Loader Accessor into Graph QL Type=
  • For the Graph QL field, define the loader

Add to Starup Services

        public void ConfigureServices(IServiceCollection services)
        {
...
            services.AddGraphQL(o => { o.ExposeExceptions = false; })
                .AddGraphTypes(ServiceLifetime.Scoped)
                .AddDataLoader();
        }

Define a Lookup Function in Repository

    public class ProductReviewRepository
    {
...
        public async Task<ILookup<int, ProductReview>> GetForProducts(IEnumerable<int> productIds)
        {
            var reviews = await _dbContext.ProductReviews.Where(pr => productIds.Contains(pr.ProductId)).ToListAsync();
            return reviews.ToLookup(r => r.ProductId);
        }

Inject Loader Accessor into Graph QL Type

    public class ProductType : ObjectGraphType<Product>
    {
        //        public ProductType(ProductReviewRepository reviewRepository)
        public ProductType(
            ProductReviewRepository reviewRepository,
            IDataLoaderContextAccessor dataLoaderAccessor)
        {
...

For the Graph QL field, define the loader

    public class ProductType : ObjectGraphType<Product>
    {
...
            Field<ListGraphType<ProductReviewType>>(
                "Reviews",
                resolve: context =>
                {
                    // Create the loader passing
                    // Name of the loader Key
                    // The Function to call on the repository
                    //     this returns a look up by product id, ProductReview
                    var loader =
                        dataLoaderAccessor.Context.GetOrAddCollectionBatchLoader<int, ProductReview>(
                                "GetReviewsByProductId",
                                reviewRepository.GetForProducts);

                    return loader.LoadAsync(context.Source.Id);
                });

Add Arguments To Query

Introduction

  • Add Support to Repository to Get One Item
  • Create A Query For Graph QL Type

Add Support to Repository to Get One Item

        public async Task<Product> GetOne(int id)
        {
            return await _dbContext.Products.SingleOrDefaultAsync(p => p.Id == id);
        }

Create A Query For Graph QL Type

Add the arguments you want with the name for the argument along with a context to suppport it.

    public class CarvedRockQuery : ObjectGraphType
    {
        public CarvedRockQuery(ProductRepository productRepository)
        {
...
            Field<ProductType>(
                "product",
                arguments: new QueryArguments(
                    new QueryArgument<NonNullGraphType<IdGraphType>> { Name = "id" }),
                resolve: context =>
                {
                    var id = context.GetArgument<int>("id");
                    return productRepository.GetOne(id);
                });