Git Product home page Git Product logo

graphql-workshop's Introduction

ChilliCream

Getting started with GraphQL on ASP.NET Core and Hot Chocolate - Workshop

If you want to browse the GraphQL server head over here.

Prerequisites

For this workshop we need a couple of prerequisites. First, we need the .NET SDK 5.0.

Then we need some IDE/Editor in order to do some proper C# coding, you can use VSCode or if you have already on your system Visual Studio or JetBrains Rider.

Last but not least we will use our GraphQL IDE Banana Cake Pop.

Note: When installing Visual Studio you only need to install the ASP.NET and web development workload.

What you'll be building

In this workshop, you'll learn by building a full-featured GraphQL Server with ASP.NET Core and Hot Chocolate from scratch. We'll start from File/New and build up a full-featured GraphQL server with custom middleware, filters, subscription and relay support.

Database Schema:

Database Schema Diagram

GraphQL Schema:

The GraphQL schema can be found here.

Sessions

Session Topics
Session #1 Building a basic GraphQL server API.
Session #2 Controlling nullability.
Session #3 Understanding GraphQL query execution and DataLoader.
Session #4 GraphQL schema design approaches.
Session #5 Understanding middleware.
Session #6 Adding complex filter capabilities.
Session #7 Adding real-time functionality with subscriptions.
Session #8 Testing the GraphQL server.

graphql-workshop's People

Contributors

3schwartz avatar abdullah-ongit avatar agr avatar arrumanov avatar buzzology avatar damikun avatar enough7 avatar gojanpaolo avatar iorlandoni avatar jeffokaki avatar jerbersoft avatar jstnedr avatar lemol avatar macke800 avatar mcbubble avatar michaelstaib avatar moigarm avatar pierrechambenoit avatar seangwright avatar snic avatar unrulyeon avatar ztolley avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

graphql-workshop's Issues

I've just ran into the problem at the end of part 4

Hi,

I've just run into the problem at the end of part 4. I'm getting the following error:

query GetSpeaker {
  speaker(id: 1) {
    name
  }
}

>>

{
  "errors": [
    {
      "message": "The ID `1` has an invalid format."
    }
  ]
}

My version of app is available here https://github.com/Sebosek/ConferencePlanner, probably I missing something.

The SpeakerQueries contains ID attribute with type int,

namespace ConferencePlanner.GraphQl.Speakers
{
    [ExtendObjectType(Name = Consts.QUERY)]
    public class SpeakerQueries
    {
        [UseApplicationDbContext]
        public Task<List<Speaker>> GetSpeakersAsync([ScopedService] ApplicationDbContext context) =>
            context.Speakers.ToListAsync();

        public Task<Speaker> GetSpeakerAsync(
            [ID(nameof(Speaker))] int id, 
            SpeakerByIdDataLoader dataLoader,
            CancellationToken cancellationToken) => dataLoader.LoadAsync(id, cancellationToken);
        
        public async Task<IReadOnlyCollection<Speaker>> GetSpeakersAsync(
            [ID(nameof(Speaker))] int[] ids, 
            SpeakerByIdDataLoader dataLoader,
            CancellationToken cancellationToken) => 
            await dataLoader.LoadAsync(ids, cancellationToken).ConfigureAwait(false);
    }
}

The SpeakerType contains ImplementationNode,

namespace ConferencePlanner.GraphQl.Types
{
    public class SpeakerType : ObjectType<Speaker>
    {
        protected override void Configure(IObjectTypeDescriptor<Speaker> descriptor)
        {
            descriptor
                .ImplementsNode()
                .IdField(p => p.Id)
                .ResolveNode(WithDataLoader);
            
            descriptor
                .Field(f => f.SessionSpeakers)
                .ResolveWith<SpeakerResolvers>(t => t.GetSessionsAsync(default!, default!, default!, default))
                .UseDbContext<ApplicationDbContext>()
                .Name("sessions");
        }

        private static Task<Speaker> WithDataLoader(IResolverContext context, int id) =>
            context.DataLoader<SpeakerByIdDataLoader>().LoadAsync(id, context.RequestAborted);
        
        private class SpeakerResolvers
        {
            public async Task<IReadOnlyCollection<Session>> GetSessionsAsync(
                Speaker speaker,
                [ScopedService] ApplicationDbContext dbContext,
                SessionByIdDataLoader sessionById,
                CancellationToken cancellationToken)
            {
                var ids = await dbContext.Speakers
                    .Where(w => w.Id == speaker.Id)
                    .Include(i => i.SessionSpeakers)
                    .SelectMany(s => s.SessionSpeakers.Select(e => e.SessionId))
                    .ToListAsync(cancellationToken)
                    .ConfigureAwait(false);

                return await sessionById.LoadAsync(ids, cancellationToken);
            }
        }
    }
}

And in ConfigureServices Relay is enabled

public void ConfigureServices(IServiceCollection services)
{
    services.AddSingleton(CreateAutomapper());
    services.AddPooledDbContextFactory<ApplicationDbContext>(options => 
        options.UseSqlite(CONNECTION_STRING).UseLoggerFactory(ApplicationDbContext.DbContextLoggerFactory));
    services
        .AddGraphQLServer()
        .AddQueryType(d => d.Name(Consts.QUERY))
            .AddTypeExtension<SpeakerQueries>()
            .AddTypeExtension<SessionQueries>()
            .AddTypeExtension<TrackQueries>()
        .AddMutationType(d => d.Name(Consts.MUTATION))
            .AddTypeExtension<SpeakerMutations>()
            .AddTypeExtension<SessionMutations>()
            .AddTypeExtension<TrackMutations>()
        .AddType<AttendeeType>()
        .AddType<SessionType>()
        .AddType<SpeakerType>()
        .AddType<TrackType>()
        .EnableRelaySupport()
        .AddDataLoader<SpeakerByIdDataLoader>()
        .AddDataLoader<SessionByIdDataLoader>();
}

Any idea, what should I check?

[Session 3] Speaker schema not updated

image

 public class SpeakerType : ObjectType<Speaker>
    {
        protected override void Configure(IObjectTypeDescriptor<Speaker> descriptor)
        {
            descriptor
                .Field(t => t.SessionSpeakers)
                .ResolveWith<SpeakerResolvers>(t => t.GetSessionsAsync(default!, default!, default!, default))
                .UseDbContext<ApplicationDbContext>()
                .Name("sessions");
        }

        private class SpeakerResolvers
        {
            public async Task<IEnumerable<Session>> GetSessionsAsync(
                Speaker speaker,
                ApplicationDbContext dbContext,
                SessionByIdDataLoader sessionById,
                CancellationToken cancellationToken)
            {
                int[] sessionIds = await dbContext.Speakers
                    .Where(s => s.Id == speaker.Id)
                    .Include(s => s.SessionSpeakers)
                    .SelectMany(s => s.SessionSpeakers.Select(t => t.SessionId))
                    .ToArrayAsync();

                return await sessionById.LoadAsync(sessionIds, cancellationToken);
            }
        }
    }
            builder.Services
              .AddGraphQLServer()
              .RegisterDbContext<ApplicationDbContext>(DbContextKind.Pooled)
              .AddQueryType<Query>()
              .AddMutationType<SpeakerMutation>()
              .AddType<SpeakerType>()
              .AddDataLoader<SpeakerByIdDataLoader>()
              .AddDataLoader<SessionByIdDataLoader>();

I've updated the speaker model, added the speakerType, ran the migration and updated the database, however the schema in the browser still does not show the SessionSpeakers collection.
image
Has there been any changes between the versions?

Session #6 "GetSessionsContaining2InTitle" "Cannot access a disposed context instance." in v12.4.1

After upgrading Session #6's HotChocolate.AspNetCore and HotChocolate.Data to version 12.4.1 running

query GetSessionsContaining2InTitle {
  sessions(where: { title: { contains: "2" } }) {
    nodes {
      title
    }
  }
}

gives error

{
"errors": [
 {
   "message": "Unexpected Execution Error",
   "locations": [
     {
       "line": 2,
       "column": 3
     }
   ],
   "path": [
     "sessions"
   ],
   "extensions": {
     "message": "Cannot access a disposed context instance. A common cause of this error is disposing a context instance that was resolved from dependency injection and then later trying to use the same context instance elsewhere in your application. This may occur if you are calling 'Dispose' on the context instance, or wrapping it in a using statement. If you are using dependency injection, you should let the dependency injection container take care of disposing context instances.\r\nObject name: 'ApplicationDbContext'.",
     "stackTrace": "   at Microsoft.EntityFrameworkCore.DbContext.CheckDisposed()\r\n   at Microsoft.EntityFrameworkCore.DbContext.get_DbContextDependencies()\r\n   at Microsoft.EntityFrameworkCore.DbContext.get_Model()\r\n   at Microsoft.EntityFrameworkCore.Internal.InternalDbSet`1.get_EntityType()\r\n   at Microsoft.EntityFrameworkCore.Internal.InternalDbSet`1.CheckState()\r\n   at Microsoft.EntityFrameworkCore.Internal.InternalDbSet`1.get_EntityQueryable()\r\n   at Microsoft.EntityFrameworkCore.Internal.InternalDbSet`1.System.Linq.IQueryable.get_Provider()\r\n   at System.Linq.Queryable.Where[TSource](IQueryable`1 source, Expression`1 predicate)\r\n   at HotChocolate.Data.Filters.Expressions.QueryableFilterProvider.<>c__DisplayClass11_0`1.<CreateApplicatorAsync>b__0(IResolverContext context, Object input)\r\n   at HotChocolate.Data.Filters.Expressions.QueryableFilterProvider.<>c__DisplayClass10_0`1.<<CreateExecutor>g__ExecuteAsync|1>d.MoveNext()\r\n--- End of stack trace from previous location ---\r\n   at HotChocolate.Types.Pagination.PagingMiddleware.InvokeAsync(IMiddlewareContext context)\r\n   at HotChocolate.Utilities.MiddlewareCompiler`1.ExpressionHelper.AwaitTaskHelper(Task task)\r\n   at HotChocolate.Execution.Processing.Tasks.ResolverTask.ExecuteResolverPipelineAsync(CancellationToken cancellationToken)\r\n   at HotChocolate.Execution.Processing.Tasks.ResolverTask.TryExecuteAsync(CancellationToken cancellationToken)"
   }
 }
],
"data": {
 "sessions": null
}
}

But, removing disposeAsync: (s, c) => c.DisposeAsync() argument from descriptor.UseScopedService in ObjectFieldDescriptorExtensions class's UseDbContext method resolved the error.

public static class ObjectFieldDescriptorExtensions
 {
     public static IObjectFieldDescriptor UseDbContext<TDbContext>(
         this IObjectFieldDescriptor descriptor)
         where TDbContext : DbContext
     {
         return descriptor.UseScopedService<TDbContext>(
             create: s => s.GetRequiredService<IDbContextFactory<TDbContext>>().CreateDbContext());
     }

     public static IObjectFieldDescriptor UseUpperCase(
         this IObjectFieldDescriptor descriptor)
     {
         return descriptor.Use(next => async context =>
         {
             await next(context);

             if (context.Result is string s)
             {
                 context.Result = s.ToUpperInvariant();
             }
         });
     }
 }

So, my question is that Is explicitly adding disposeAsync attribute necessary for disposing of the DbContext?

IArgumentDescriptor.Type function problem

I'm trying to write my QueryType using ObjectType and IObjectTypeDescriptor,

My Id field are Guid types, the following code output 2 queries, the 1st one works fine. the 2nd one does not.

descriptor
.Field($"sessionById")
.Argument("id", a => a.ID().Type(typeof(Guid))) // add Input Argument
.UseDbContext()
.ResolverWith(r=> ...);

descriptor
.Field($"sessionListById")
.Argument("ids", a => a.ID().Type(typeof(Guid[]))) // add Input Argument
.UseDbContext()
.ResolverWith(r=> ...);

I have 2 problems:
Problem 1:
The argument for the 2nd query will be output to : ids: [ID!] , instead of ids: [ID!]! --- should be not null field.

Problem 2:
when I plug my ID value into the 2nd query input, I got the following error telling me the IDs have an invalid format.

The same ID works for the first query when input just uses single ID instead of an Array.

query GetSessions {
a: sessionListById(ids: ["U2Vzc2lvbgpnNWUxZmEzNWU3YWFiNGZkMmI0ZWM5YTM1YjE1OTY1NjQ="])
{
id,
title
}
b: sessionById(id: "U2Vzc2lvbgpnNWUxZmEzNWU3YWFiNGZkMmI0ZWM5YTM1YjE1OTY1NjQ=")
{
id,
title
}
}

Result:
{
"errors": [
{
"message": "The IDs U2Vzc2lvbgpnNWUxZmEzNWU3YWFiNGZkMmI0ZWM5YTM1YjE1OTY1NjQ= have an invalid format."
}
],
"data": {
"a": null,
"b": {
"id": "U2Vzc2lvbgpnNWUxZmEzNWU3YWFiNGZkMmI0ZWM5YTM1YjE1OTY1NjQ=",
"title": "Session 5"
}
}
}

Anyone can help?

Should the latter GetAttendeeAsync in SessionAttendeeCheckIn be GetSessionAsync instead?

The class SessionAttendeeCheckIn currently have two definitions of GetAttendeeAsync

public Task<Attendee> GetAttendeeAsync(
AttendeeByIdDataLoader attendeeById,
CancellationToken cancellationToken) =>
attendeeById.LoadAsync(AttendeeId, cancellationToken);
public Task<Session> GetAttendeeAsync(
SessionByIdDataLoader sessionById,
CancellationToken cancellationToken) =>
sessionById.LoadAsync(AttendeeId, cancellationToken);

But it seems to me that the latter should be GetSessionAsync instead. Or am I missing something?

That part is specifically covered in 7-subscriptions.
... # 2 in https://github.com/ChilliCream/graphql-workshop/blob/master/docs/7-subscriptions.md#add-onattendeecheckedin-subscription

I'll be happy to create a PR if it needs correction

Btw, thank you for creating this workshop. I'm learning graphql and I'm having a great learning experience so far.

Session 3 - missing explanation (reference) of using ToListAsync instead of IQueryable

In Session 3 found

Important: Note, that we no longer are returning the IQueryable but are executing the IQueryable by using ToListAsync. We will explain why later in the middleware and filter session.

But where to find it explanation? In Session 5 something about middleware, but in 6-th there is... IQueryable, again! How this magic works?

[UseApplicationDbContext]
[UsePaging]
public IQueryable<Track> GetTracks(
    [ScopedService] ApplicationDbContext context) =>
    context.Tracks.OrderBy(t => t.Name);

I've tried in my project:

[UsePersonDbContext]
[UseProjection]
public IQueryable<EducactionLevel> GetEducactionLevels(
    [ScopedService] PersonDbContext context)
{
    return context.EducactionLevels;
}

where PersonDbContext is registered by services.AddPooledDbContextFactory<PersonDbContext>(...), but got

Cannot access a disposed context instance. A common cause of this error is disposing a context instance that was resolved from dependency injection and then later trying to use the same context instance elsewhere in your application. This may occur if you are calling 'Dispose' on the context instance, or wrapping it in a using statement. If you are using dependency injection, you should let the dependency injection container take care of disposing context instances.
Object name: 'PersonDbContext'.

So question is:

  • How to use projections with PooledDbContextFactory?

Relay ID error " has an invalid format."

Hello,

I'm following the tutorial and during step 4 in the part that adds relay support to the schema I'm getting the error The ID 1 has an invalid format.

I tried with the provided code but got the same error.

My query is:

{
  node (id: "1") {
    id
    ... on Speaker {
      bio
    }
  }
}

and

{
  speaker (id: 1) {
    bio
  }
}

Error at Session #3: GraphQL schema design approaches

Hello, I'm trying to complete the third part of this tutorial and I can't get past the definition of more types. Everything works well till the "Enable Relay support" section. But when I try to add more data loaders and schema types, my program crashes with this error message:

"An unhandled exception of type 'HotChocolate.SchemaException' occurred in System.Private.CoreLib.dll
The name Mutation was already registered by another type. - Type: Mutation"

I tried to rewrite it twice, to find the source of the error, but I didn't come up with anything. I would be grateful if there was someone who could look at it. Here is my project repository.

error after step 3 - using v12

The updated "complete" sample code shows using v12. However, when I get the following error after adding the dataloader classes in step 3.

{
  "errors": [
    {
      "message": "There was no argument with the name `speaker` found on the field `sessions`.",
      "locations": [
        {
          "line": 4,
          "column": 5
        }
      ],
      "path": [
        "speakers",
        0,
        "sessions"
      ],
      "extensions": {
        "fieldName": "sessions",
        "argumentName": "speaker"
      }
    }
  ]
}

Doc correction in 3-understanding-dataLoader.md

3-understanding-dataLoader.md, section Fluent type configurations, Step 4. - Description says to add SessionType class. Code example shows SpeakerType instead. I think SessionType should be SpeakerType. Step 7. Query should be for speakers instead of speaker since no id is provided

Add EF .config folder to .gitignore - dotnet-tools.json problem based on location zone..

Problem:
In some machines you can have problem to use ef because of dotnet-tools.json was created on different machine.. And is included in project... Windows use location timestamp

Location:
https://github.com/ChilliCream/graphql-workshop/tree/master/code/complete/.config (and all others)

Error

File  ..../graphql-workshop-master\graphql-workshop-master\code\complete\.config\dotnet-tools.json came from another computer and might be blocked to help protect this computer. For more information, including how to unblock, see https://aka.ms/motw

image

Removing of course solve the problem..

Recommendation
Moving all this .config folders to .gitignore (not needed to update database)... If needed and people follow workshop tools will be installed from it...

Is this extension and attribute still relevant?

From page 3 this extension and attribute are asked to be made. It seems these are in the Types and Data namespace in newer versions of HC? Are they the same or is this a bit outdated?


using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using HotChocolate.Types;

namespace ConferencePlanner.GraphQL
{
    public static class ObjectFieldDescriptorExtensions
    {
        public static IObjectFieldDescriptor UseDbContext<TDbContext>(
            this IObjectFieldDescriptor descriptor)
            where TDbContext : DbContext
        {
            return descriptor.UseScopedService<TDbContext>(
                create: s => s.GetRequiredService<IDbContextFactory<TDbContext>>().CreateDbContext(),
                disposeAsync: (s, c) => c.DisposeAsync());
        }
    }
}
The UseDbContext will create a new middleware that handles scoping for a field. The create part will rent from the pool a DBContext, the dispose part will return it after the middleware is finished. All of this is handled transparently through the new IDbContextFactory<T> introduced with .NET 5.

Create another file located in Extensions called UseApplicationDbContextAttribute.cs with the following code:

using System.Reflection;
using ConferencePlanner.GraphQL.Data;
using HotChocolate.Types;
using HotChocolate.Types.Descriptors;

namespace ConferencePlanner.GraphQL
{
    public class UseApplicationDbContextAttribute : ObjectFieldDescriptorAttribute
    {
        public override void OnConfigure(
            IDescriptorContext context,
            IObjectFieldDescriptor descriptor,
            MemberInfo member)
        {
            descriptor.UseDbContext<ApplicationDbContext>();
        }
    }
}```

Subscription is closed with the error "Value cannot be null. (Parameter 'payload')" when need to return null

EROR always when need return null.

Calling await sender.SendAsync($"CaseInProgress_{runId}", (int?)null);

public class CaseInProgressChangedPayload
  {
    public int? CaseInProgress { get; set; }
  }

  [Subscribe]
  [Topic("CaseInProgress_{runId}")]
  public CaseInProgressChangedPayload OnCaseInProgressChanged(int runId, [EventMessage] int? caseInProgress)
  {
    return new CaseInProgressChangedPayload
    {
      CaseInProgress = caseInProgress
    };
  }

OR
[Subscribe]
  [Topic("CaseInProgress_{runId}")]
  public int? OnCaseInProgressChanged(int runId, [EventMessage] int? caseInProgress) => caseInProgress;

OR
[Subscribe]
  [Topic("CaseInProgress_{runId}")]
  public int? OnCaseInProgressChanged(int runId, [EventMessage] int? caseInProgress)
  {
    return caseInProgress;
  }

Full log:
{"type":"connection_ack"}
{
"id": "91f6db40-c442-45d3-b0d3-bf792ed379ee",
"type": "error",
"payload": [
{
"message": "Value cannot be null. (Parameter 'payload')",
"extensions": {
"message": "Value cannot be null. (Parameter 'payload')",
"stackTrace": " at HotChocolate.Execution.Instrumentation.SubscriptionEventContext..ctor(ISubscription subscription, Object payload)\r\n at HotChocolate.Execution.Processing.SubscriptionExecutor.Subscription.OnEvent(Object payload)\r\n at HotChocolate.Execution.Processing.SubscriptionExecutor.SubscriptionEnumerator.MoveNextAsync()\r\n at HotChocolate.AspNetCore.Subscriptions.OperationSession.SendResultsAsync(GraphQLRequest request, CancellationToken cancellationToken)\r\n at HotChocolate.AspNetCore.Subscriptions.OperationSession.SendResultsAsync(GraphQLRequest request, CancellationToken cancellationToken)\r\n at HotChocolate.AspNetCore.Subscriptions.OperationSession.SendResultsAsync(GraphQLRequest request, CancellationToken cancellationToken)"
}
}
]
}

Data Annotations

Hi. I noticed that data annotations like [StringLength(100)] or [MinLength(10), MaxLength(20)] have no effect on generated database. For example Data/Speaker class from Session 6 looks in SQL like this:

CREATE TABLE "Speakers" (
    "Id" INTEGER NOT NULL CONSTRAINT "PK_Speakers" PRIMARY KEY AUTOINCREMENT,
    "Name" TEXT NOT NULL,
    "Bio" TEXT NULL,
    "WebSite" TEXT NULL)

Is this correct behaviour?

AddTypeExtension vs AddType

In 4-schema-design, AddTypeExtension and AddType is used interchangeably. I'm curious as well as confused because of this. I'll probably be able to clarify this later when I get to learn more about graphql and hc. But any response will be greatly appreciated.

e.g.

  1. Head back to the Startup.cs and add the TrackMutations to the schema builder.
  services
      .AddGraphQLServer()
      .AddQueryType(d => d.Name("Query"))
          .AddTypeExtension<SpeakerQueries>()
      .AddMutationType(d => d.Name("Mutation"))
          .AddTypeExtension<SessionMutations>()
          .AddTypeExtension<SpeakerMutations>()
          .AddTypeExtension<TrackMutations>()
      .AddType<AttendeeType>()
      .AddType<SessionType>()
      .AddType<SpeakerType>()
      .AddType<TrackType>()
      .EnableRelaySupport()
      .AddDataLoader<SpeakerByIdDataLoader>()
      .AddDataLoader<SessionByIdDataLoader>();

  1. Again, head over to the Startup.cs and register the TrackQueries with the schema builder.

    services
         .AddGraphQLServer()
         .AddQueryType(d => d.Name("Query"))
             .AddType<SessionQueries>()
             .AddType<SpeakerQueries>()
             .AddType<TrackQueries>()
         .AddMutationType(d => d.Name("Mutation"))
             .AddType<SessionMutations>()
             .AddType<SpeakerMutations>()
             .AddType<TrackMutations>()
         .AddType<AttendeeType>()
         .AddType<SessionType>()
         .AddType<SpeakerType>()
         .AddType<TrackType>()
         .EnableRelaySupport();

Session #1: Server cannot be reached

Hi. I started with new version of tutorials and get stuck in first session. I downloaded Session 1, builded project, generated DB and tried to fetch some data over Banana Cake Pop which ended up with error

 {
  "name": "ServerNetworkError",
  "statusText": "Failed to fetch"
}

Then I tried to install playground and run it in browser. Same issue.

Do anyone have the same problem or is it just on my side?

EDIT: Sessions 2 and 6 both have the same problem.
EDIT2: Problem is that HTTPS port 5001 cannot be accessed. HTTP 5000 works fine.

Is `NonNullType` still necessary when nullable reference types is enabled?

Session # 2 demonstrates how HC leverages C#'s nullable reference types.
In Session # 6 NonNullType is used...

.ResolveWith<TrackResolvers>(t => t.GetSessionsAsync(default!, default!, default))
.UsePaging<NonNullType<SessionType>>()

...but it looks like it doesn't affect the generated schema at all.

The graphql type nullability is controlled by nullable reference types:

  • Task<IEnumerable<Session>> GetSessionsAsync for non-nullable Session
  • Task<IEnumerable<Session?>> GetSessionsAsync for nullable Sessions

Is it ok to remove the use of NonNullType if nullable reference types is enabled?

RenameSession Error

Hi! I want to try the get started found here: https://chillicream.com/docs/strawberryshake/get-started and the following project is generated. I found that the RenameSession is not work correctly after click the Save button. The problem occurred in the graphql server .

The error msg as follows:
https://files.slack.com/files-pri/TD98NH6TS-F02RX8AQ5FZ/image.png
https://files.slack.com/files-pri/TD98NH6TS-F02RVR6BTEK/image.png

And the function should be modified as follows:

[UseApplicationDbContext]
    public async Task<RenameSessionPayload> RenameSessionAsync(
        RenameSessionInput input,
        [ScopedService] ApplicationDbContext context,
        [Service]ITopicEventSender eventSender)
    {
        var session = await context.Sessions.FindAsync( int.Parse( input.SessionId));

        if (session is null)
        {
            return new RenameSessionPayload(
                new UserError("Session not found.", "SESSION_NOT_FOUND"));
        }

        session.Title = input.Title;

        await context.SaveChangesAsync();

        await eventSender.SendAsync(
            nameof(SessionSubscriptions.OnSessionScheduledAsync),
            session.Id);

        return new RenameSessionPayload(session);
    }

Cannot access a disposed context exception in HotChocolate V12

The graphql-workshop provided me a very detailed introduction to HotChocolate features. All features and code worked correctly with V11.
However, after I ungraded HotChocolate libraries to V12.9.0, I hit the following exception during query execution:
Cannot access a disposed context instance. A common cause of this error is disposing a context instance that was resolved from dependency injection and then later trying to use the same context instance elsewhere in your application. This may occur if you are calling 'Dispose' on the context instance, or wrapping it in a using statement. If you are using dependency injection, you should let the dependency injection container take care of disposing context instances.\r\nObject name: 'ApplicationDbContext'.

After reading through your detailed V12 documentation here:
https://chillicream.com/docs/hotchocolate/integrations/entity-framework.
I suspect the issue must be related to enhanced disposeasync logic in V12. The query executions worked fine again after I commented the manual disposeAsync logic as shown here.

    public static IObjectFieldDescriptor UseDbContext<TDbContext>(
        this IObjectFieldDescriptor descriptor)
        where TDbContext : DbContext
    {
        return descriptor.UseScopedService<TDbContext>(
            create: s => s.GetRequiredService<IDbContextFactory<TDbContext>>().CreateDbContext());
        //return descriptor.UseScopedService<TDbContext>(
        //    create: s => s.GetRequiredService<IDbContextFactory<TDbContext>>().CreateDbContext(),
        //    disposeAsync: (s, c) => c.DisposeAsync());
    }

If possible it would help to include V12 and V13 enhanced features into your excellent workshop sample. I plan to implement HotChocolate V12 for my future projects. Thank you.

Session 3 - final query ended with errors

Executing the last query GetSpeakerWithSessions on session 3 I have the following error:

{
  "errors": [
    {
      "message": "There was no argument with the name `speaker` found on the field `sessions`.",
      "locations": [
        {
          "line": 4,
          "column": 8
        }
      ],
      "path": [
        "speakers",
        0,
        "sessions"
      ],
      "extensions": {
        "fieldName": "sessions",
        "argumentName": "speaker"
      }
    }
  ]
}

I'm following the workshop trying to implement all the flow using ASP.NET Core 6 and HotChocolate version 12.7.0.
Source code is available here: https://github.com/albx/graphql-workshop/tree/part-3

Am I missing something?
Thank you very much for your help!

There was no argument with the name `speaker` found on the field `sessions

version 12.0.1
In the Fluent Type configuration section, step 4 of 3-understanding-dataloader.md, the code

   private class SpeakerResolvers
        {
            public async Task<IEnumerable<Session>> GetSessionsAsync(
                Speaker speaker,
                [ScopedService] ApplicationDbContext dbContext,
                SessionByIdDataLoader sessionById,
                CancellationToken cancellationToken)
            {
                int[] sessionIds = await dbContext.Speakers
                    .Where(s => s.Id == speaker.Id)
                    .Include(s => s.SessionSpeakers)
                    .SelectMany(s => s.SessionSpeakers.Select(t => t.SessionId))
                    .ToArrayAsync();

                return await sessionById.LoadAsync(sessionIds, cancellationToken);
            }
        }

throws the error :

There was no argument with the name speaker found on the field `sessions

If the Speaker parameter is annotated with [Parent] then everything works. I have not verified it but I assume that the SessionResolvers and AttendeeResolvers defined in 4-schema-design.md have the same issue.

The section in the user guide regarding arguments for resolvers is really sketchy. It would be very helpful if the paragraph

There are also specific arguments that will be automatically populated by Hot Chocolate when the resolver is executed. These include Dependency injection services, DataLoaders, state, or even context like a parent value.

was elaborated. From what is written I understand that any registered service can be injected but I have no idea what is meant by

state, or even context like a parent value

Error in SpeakerType.cs on page 3-understanding-dataLoader.md ?

Following the docs until the explanation of [Fluent Type Configurations on page 3-understanding-dataLoader.md] (https://github.com/ChilliCream/graphql-workshop/blob/master/docs/3-understanding-dataLoader.md#fluent-type-configurations).
Executing query

query GetSpeakerWithSessions { speakers { name sessions { title } } }

Should produce list of speakers with empty sessions list
Produces instead "There was no argument with the name speaker found on the field sessions." for each speaker on line 4 column 5 of the query.

Dev can't follow Session 6 as it requires missing mutatutions

In Session 6 it talks about adding pagination and demonstrates that with a query for tracks to include paginated sessions.

Unfortunately at that point int he workshop there is no way to add a track and associate or schedule sessions to it.

I think the mutation comes later on but without it the dev gets an error. Also would it be possible to include some example queries to cut and paste to help populate the DB to be able to follow the workshop?

Track queries throws DbContext exceptions with paginations

I have been battling with the Track queries with pagination in Session 6 for several hours without success. Later I got to realize that the Field descriptor for Sessions needed to be provided with "UseDbContext" middleware in the TrackType.

However the tutorials lack that middleware, is it an error or I was not doing it right.

image

Session 3: UseApplicationDbContextAttribute not necessary?

I'm trying to understand why creating a separate UseApplicationDbContextAttribute (and the IObjectFieldDescriptor extension) would be necessary at all (steps 5+6 and usage later). I've been loosely following the examples and could not force/reproduce the parallel execution error. Digging into the sources, I found that the default UseDbContext attribute that's coming with the EntityFramework package forwards to a built-in extension method for IObjectFieldDescriptor that's basically already doing the same thing like the manually implemented logic in session 3, doesn't it?

Am I correct that this separate implementation on the application level is not necessary anymore?

Nested queries with relationship 1:M FK?

i have a 1:M relationship an need nested query

Example

i have one table client with id 1

and table sales with any sales data with client id 1

my result in playground

"data": { "cliente": { "nOMBRE": "juanito", "ventasByRut": [ null, null, null ] } } }

code:

` public async Task<IEnumerable> GetVentasAsync(
Cliente cliente,
[ScopedService] DataContext dataContext,
VentaByIdDataLoader ventaById,
CancellationToken cancellationToken)
{
int[] ventaIds = await dataContext.VENTA
.Where(s => s.CLIENTERUT == cliente.RUT)
.Select(s => s.CLIENTERUT)
.ToArrayAsync();

            return await ventaById.LoadAsync(ventaIds, cancellationToken);
                
        }`

console SQL log :

info: Microsoft.EntityFrameworkCore.Database.Command[20101]
Executed DbCommand (162ms) [Parameters=[], CommandType='Text', CommandTimeout='0']
SELECT "c"."RUT", "c"."NOMBRE"
FROM "CLIENTE" "c"
WHERE ("c"."RUT" = 12333444)
info: Microsoft.EntityFrameworkCore.Database.Command[20101]
Executed DbCommand (41ms) [Parameters=[:cliente_RUT_0='12333444'], CommandType='Text', CommandTimeout='0']
SELECT "v"."CLIENTERUT"
FROM "VENTA" "v"
WHERE ("v"."CLIENTERUT" = :cliente_RUT_0)
info: Microsoft.EntityFrameworkCore.Database.Command[20101]
Executed DbCommand (1ms) [Parameters=[], CommandType='Text', CommandTimeout='0']
SELECT "v"."IDVENTA", "v"."CANTIDAD", "v"."CLIENTERUT", "v"."MONTO", "v"."PRECIO"
FROM "VENTA" "v"
WHERE ("v"."IDVENTA" = 12333444)

Can't Get Step 1 of the Tutorial Working

AddSpeaker Mutation doesn't show up in the client tool in the Conference Planner tutorial. I can't access the standalone client so I'm using the middleware test page.

Suggest Not Including data context discussion in "understanding-dataloader.md"

I would suggest not teaching people to setup the project incorrectly but go directly to setting up correctly with attribute that supports the middleware. Maybe in passing mention the wrong way to set it up but no need to go through all the details. Most people will just follow what you suggest.

That is, explain the setup in the first chapter, then have the dataloader discussion just be about dataloader.

[ScopedService] is Obsolete, but using [Service(ServiceKind.Pooled)] fails

As per GraphQL-Workshop and Session #3 Understanding GraphQL query execution and DataLoader

I followed Steps 3, 4, 5, 6 & 7 and everything worked as expected.
But Warning is shown while using [ScopedService] that it is Obsolete and I should use [Service(ServiceKind.Pooled)] or [Service(ServiceKind.Resolver)].
But when I use either [Service(ServiceKind.Pooled)] or [Service(ServiceKind.Resolver)] then getting error as following.

"No service for type 'Microsoft.Extensions.ObjectPool.ObjectPool`1[ApplicationDbContext]' has been registered."

Where is schema stiching?

Hi,
Couldn't find anything on schema stiching. Will any new episode on this be added recently?
Thanks

The field `id` does not exist on the type `CommandsConnection`.

Full error:

{
"errors": [
{
"message": "The field id does not exist on the type CommandsConnection.",
"locations": [
{
"line": 59,
"column": 9
}
],
"path": [
"addCommandsIdentifier",
"commandsIdentifier",
"commands"
],
"extensions": {
"type": "CommandsConnection",
"field": "id",
"responseName": "id",
"specifiedBy": "http://spec.graphql.org/October2021/#sec-Field-Selections-on-Objects-Interfaces-and-Unions-Types"
}
},
{
"message": "The field content does not exist on the type CommandsConnection.",
"locations": [
{
"line": 60,
"column": 9
}
],
"path": [
"addCommandsIdentifier",
"commandsIdentifier",
"commands"
],
"extensions": {
"type": "CommandsConnection",
"field": "content",
"responseName": "content",
"specifiedBy": "http://spec.graphql.org/October2021/#sec-Field-Selections-on-Objects-Interfaces-and-Unions-Types"
}
}
]
}

the type:

`
protected override void Configure(IObjectTypeDescriptor descriptor)
{
descriptor
.ImplementsNode()
.IdField(t => t.Id)
.ResolveNode((ctx, id) => ctx.DataLoader().LoadAsync(id, ctx.RequestAborted));

        descriptor
            .Field(t => t.Commands)
            .ResolveWith<CommandResolvers>(t => t.GetCommandsAsync(default!, default!, default!, default))
            .UseDbContext<ApplicationDbContext>()
            .UsePaging<NonNullType<CommandType>>()
            .Name("commands");
    }

`

and the query:

public class CommandQueries { [UseApplicationDbContext] [UsePaging(typeof(NonNullType<CommandType>))] public IQueryable<Command> GetCommands([ScopedService] ApplicationDbContext context) => context.Commands; }

Breaking changes Schema Explorer using 11.0.0-rc.0

I am following the workshop and I see that since the introduction of recommending to use HotChocolate.AspNetCore 11.0.0-rc.0 it introduced breaking changes for the Schema Explorer in Banana Cake Pop.

At first I believed I did something wrong, but I went on and downloaded the source code of this repository to check if the completed session 1 code is also breaking, and it is. I went through the commits of this repository to find the session 1 with the "old" API of version 10.5.X. and that worked.

I am not sure what the problems is, but I know that it is breaking here:
image

The "old" API uses the following syntax that works:
image

Why not add mutation to schema?

Adding mutation in Startup.cs

services .AddGraphQLServer() .AddQueryType<Query>() .AddMutationType<Mutation>();

and the playground don't show in the schema.

image

why dont show in the playground?

i need restart navigator? any simple solution?

Id field being returned as base64 encoded string instead of Guid

The ID is stored as a Guid in my database, but when queried through GraphQL, it is returned as a base64 encoded string.
i am facing this problem after enabling relay policy and implementing the reolver to improve data fetch. Is there a way to configure a custom serializer or scalar type for Guid values in the schema?

"There was no argument with the name `speaker` found on the field `sessions`."

When completing section 3 "Understanding Dataloaders", with the introduction of SpeakerType, and SpeakerResolvers, I'm getting the error:

{
  "errors": [
    {
      "message": "There was no argument with the name `speaker` found on the field `sessions`.",
      "locations": [
        {
          "line": 5,
          "column": 6
        }
      ],
      "path": [
        "speakers",
        0,
        "sessions"
      ],
      "extensions": {
        "fieldName": "sessions",
        "argumentName": "speaker"
      }
    }
  ]
}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.