Skip to content

Commit 5b72b2e

Browse files
committed
Add Dataloaders and error handling
1 parent efb83e9 commit 5b72b2e

File tree

7 files changed

+86
-42
lines changed

7 files changed

+86
-42
lines changed

.editorconfig

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -59,22 +59,12 @@ dotnet_naming_symbols.constant_fields.applicable_kinds = field
5959
dotnet_naming_symbols.constant_fields.required_modifiers = const
6060
dotnet_naming_style.pascal_case_style.capitalization = pascal_case
6161

62-
# static fields should have s_ prefix
63-
dotnet_naming_rule.static_fields_should_have_prefix.severity = suggestion
64-
dotnet_naming_rule.static_fields_should_have_prefix.symbols = static_fields
65-
dotnet_naming_rule.static_fields_should_have_prefix.style = static_prefix_style
66-
dotnet_naming_symbols.static_fields.applicable_kinds = field
67-
dotnet_naming_symbols.static_fields.required_modifiers = static
68-
dotnet_naming_symbols.static_fields.applicable_accessibilities = private, internal, private_protected
69-
dotnet_naming_style.static_prefix_style.required_prefix = s_
70-
dotnet_naming_style.static_prefix_style.capitalization = camel_case
71-
7262
# internal and private fields should be _camelCase
7363
dotnet_naming_rule.camel_case_for_private_internal_fields.severity = suggestion
7464
dotnet_naming_rule.camel_case_for_private_internal_fields.symbols = private_internal_fields
7565
dotnet_naming_rule.camel_case_for_private_internal_fields.style = camel_case_underscore_style
7666
dotnet_naming_symbols.private_internal_fields.applicable_kinds = field
77-
dotnet_naming_symbols.private_internal_fields.applicable_accessibilities = private, internal
67+
dotnet_naming_symbols.private_internal_fields.applicable_accessibilities = private
7868
dotnet_naming_style.camel_case_underscore_style.required_prefix = _
7969
dotnet_naming_style.camel_case_underscore_style.capitalization = camel_case
8070

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Threading;
4+
using System.Threading.Tasks;
5+
using HotChocolate.DataLoader;
6+
using OpenBreweryDB.Core.Conductors.Breweries.Interfaces;
7+
using OpenBreweryDB.Data.Models;
8+
using AndcultureCode.CSharp.Core.Extensions;
9+
using System.Linq;
10+
using OpenBreweryDB.API.GraphQL.Errors;
11+
12+
namespace OpenBreweryDB.API.GraphQL.Breweries.Dataloaders
13+
{
14+
public class BreweryByIdDataLoader : BatchDataLoader<long, Brewery>
15+
{
16+
private readonly IBreweryConductor _breweryConductor;
17+
18+
public BreweryByIdDataLoader(IBreweryConductor breweryConductor)
19+
{
20+
_breweryConductor = breweryConductor ?? throw new ArgumentNullException(nameof(breweryConductor));
21+
}
22+
23+
protected override async Task<IReadOnlyDictionary<long, Brewery>> LoadBatchAsync(
24+
IReadOnlyList<long> keys,
25+
CancellationToken cancellationToken)
26+
{
27+
var breweryResult = _breweryConductor.FindAll(b => keys.Contains(b.Id));
28+
29+
if (!breweryResult.HasErrorsOrResultIsNull())
30+
{
31+
return await Task.FromResult(breweryResult.ResultObject.ToDictionary(t => t.Id));
32+
}
33+
34+
if (breweryResult.Errors?.Any() == true)
35+
{
36+
throw new ResultException(breweryResult.Errors);
37+
}
38+
39+
return null;
40+
}
41+
}
42+
}

dotnet/OpenBreweryDB.API/GraphQL/Breweries/BreweryResolvers.cs renamed to dotnet/OpenBreweryDB.API/GraphQL/Breweries/Resolvers/BreweryResolvers.cs

Lines changed: 2 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -6,40 +6,13 @@
66
using OpenBreweryDB.Core.Conductors.Breweries.Interfaces;
77
using OpenBreweryDB.Data.Models;
88
using System.Threading.Tasks;
9-
using GeoCoordinatePortable;
109
using System.Collections.Generic;
1110

1211
namespace OpenBreweryDB.API.GraphQL.Resolvers
1312
{
14-
public static class BreweryResolvers
13+
public class BreweryResolvers
1514
{
16-
public static async Task<Brewery> BreweryNodeResolver(IResolverContext ctx, long id)
17-
{
18-
var breweryConductor = ctx.Service<IBreweryConductor>();
19-
20-
var breweryResult = breweryConductor.Find(id);
21-
22-
if (!breweryResult.HasErrorsOrResultIsNull())
23-
{
24-
return await Task.FromResult(breweryResult.ResultObject);
25-
}
26-
27-
foreach (var err in breweryResult.Errors)
28-
{
29-
ctx.ReportError(
30-
ErrorBuilder.New()
31-
.SetCode(err.Key)
32-
.SetPath(ctx.Path)
33-
.AddLocation(ctx.FieldSelection)
34-
.SetMessage(err.Message)
35-
.Build()
36-
);
37-
}
38-
39-
return null;
40-
}
41-
42-
public static async Task<IEnumerable<Brewery>> NearbyBreweriesResolver(IResolverContext ctx)
15+
public async Task<IEnumerable<Brewery>> GetNearbyBreweriesAsync(IResolverContext ctx)
4316
{
4417
var brewery = ctx.Parent<Brewery>();
4518

dotnet/OpenBreweryDB.API/GraphQL/Breweries/Types/BreweryType.cs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1+
using HotChocolate.Resolvers;
12
using HotChocolate.Types;
23
using HotChocolate.Types.Relay;
4+
using OpenBreweryDB.API.GraphQL.Breweries.Dataloaders;
35
using OpenBreweryDB.API.GraphQL.Resolvers;
46
using OpenBreweryDB.Data.Models;
57
using System;
@@ -14,7 +16,9 @@ protected override void Configure(IObjectTypeDescriptor<Brewery> descriptor)
1416
descriptor
1517
.Name("Brewery")
1618
.Description("A brewery of beer")
17-
.AsNode().IdField(t => t.Id).NodeResolver((ctx, id) => BreweryResolvers.BreweryNodeResolver(ctx, id));
19+
.AsNode()
20+
.IdField(t => t.Id)
21+
.NodeResolver((ctx, id) => ctx.DataLoader<BreweryByIdDataLoader>().LoadAsync(id, ctx.RequestAborted));
1822

1923
descriptor.Field("nearby")
2024
.Argument(
@@ -23,7 +27,7 @@ protected override void Configure(IObjectTypeDescriptor<Brewery> descriptor)
2327
.Type<IntType>()
2428
.Description("limit the nearby breweries to search radius, defaults to 25 milles")
2529
)
26-
.Resolver(BreweryResolvers.NearbyBreweriesResolver);
30+
.ResolveWith<BreweryResolvers>(r => r.GetNearbyBreweriesAsync(default));
2731

2832
descriptor.Field(t => t.BreweryType)
2933
.Type<NonNullType<StringType>>()
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
using System.Linq;
2+
using AndcultureCode.CSharp.Core.Interfaces;
3+
4+
namespace OpenBreweryDB.API.GraphQL.Errors
5+
{
6+
public class ResultErrorFilter : HotChocolate.IErrorFilter
7+
{
8+
public HotChocolate.IError OnError(HotChocolate.IError error)
9+
{
10+
return error.Exception is ResultException resultException
11+
&& resultException.Errors.FirstOrDefault() is IError firstError
12+
? error.WithCode(firstError.Key).WithMessage(firstError.Message)
13+
: error;
14+
}
15+
}
16+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using AndcultureCode.CSharp.Core.Interfaces;
4+
5+
namespace OpenBreweryDB.API.GraphQL.Errors
6+
{
7+
public class ResultException : Exception
8+
{
9+
public ResultException(List<IError> errors)
10+
{
11+
Errors = errors;
12+
}
13+
14+
public List<IError> Errors { get; }
15+
}
16+
}

dotnet/OpenBreweryDB.API/Startup.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
using OpenBreweryDB.Core.Conductors.Users.Interfaces;
2424
using OpenBreweryDB.API.GraphQL.Users;
2525
using OpenBreweryDB.API.GraphQL.Reviews;
26+
using OpenBreweryDB.API.GraphQL.Errors;
2627

2728
namespace OpenBreweryDB.API
2829
{
@@ -48,6 +49,8 @@ public void ConfigureServices(IServiceCollection services)
4849

4950
services
5051
.AddInMemorySubscriptions()
52+
.AddErrorFilter<ResultErrorFilter>()
53+
.AddDataLoaderRegistry()
5154
.AddGraphQL(sp => SchemaBuilder.New()
5255
.EnableRelaySupport()
5356
.AddServices(sp)

0 commit comments

Comments
 (0)