Skip to content

Integrations HotChocolate GraphQL

quyvu edited this page Oct 15, 2026 · 3 revisions

HotChocolate Integration

Seamlessly integrate FxMap with HotChocolate GraphQL to automatically map data in your GraphQL resolvers.

Why FxMap + HotChocolate?

HotChocolate is a powerful GraphQL server for .NET. When combined with FxMap, you can:

Automatic Data Mapping in Resolvers

Use FxMap profiles for your GraphQL types to automatically fetch and map data from multiple services.

Microservices Made Easy

GraphQL queries can seamlessly fetch data across multiple microservices without complex resolver logic.

Clean Resolver Code

Eliminate boilerplate mapping code in your resolvers - FxMap handles it all declaratively.

Installation

dotnet add package FxMap
dotnet add package FxMap.HotChocolate

Or via Package Manager Console:

Install-Package FxMap
Install-Package FxMap.HotChocolate

Configuration

Set up HotChocolate first, then register FxMap with the HotChocolate integration:

using FxMap;
using HotChocolate;
 
var builder = WebApplication.CreateBuilder(args);
 
// 1. Configure HotChocolate GraphQL Server
var registerBuilder = builder.Services.AddGraphQLServer()
    .AddQueryType<Query>()
    .AddType<MembersType>();
 
// 2. Configure FxMap with HotChocolate integration
builder.Services.AddFxMap(cfg =>
{
    cfg.AddEntitiesFromAssemblyContaining<SomeEntityAssemblyMarker>();
    cfg.AddProfilesFromAssemblyContaining<SomeProfileAssemblyMarker>();
    cfg.AddGrpcClients(c =>
        c.AddGrpcHosts("http://localhost:5001", "http://localhost:5002", "http://localhost:5003"));
    cfg.SetRetryPolicy(3, n => n * TimeSpan.FromSeconds(2),
        (e, ts) => Console.WriteLine($"Error: {e.Message}"));
})
.AddEntityFrameworkCore(cfg => cfg.AddDbContexts(typeof(Service1Context), typeof(OtherService1Context)))
.AddMongoDb(cfg => cfg.AddCollection(memberSocialCollection))
.AddHotChocolate(cfg => cfg.AddRequestExecutorBuilder(registerBuilder));
 
var app = builder.Build();
app.MapGraphQL();
app.Run();

Key Point: Pass the HotChocolate request executor builder to FxMap using .AddHotChocolate(). This enables FxMap to automatically resolve dependencies in your GraphQL queries.

Automatic Dependency Resolution

FxMap automatically detects and resolves dependencies in your GraphQL types. When a property depends on another FxMap-mapped property, FxMap resolves them in the correct order:

// GraphQL response type
public class MemberResponse
{
    public string Id { get; set; }
    public string UserId { get; set; }
    public string ProvinceId { get; set; }   // populated first
    public string CountryName { get; set; }  // populated second (depends on ProvinceId)
}
 
// One profile holds both rules
public class MemberResponseProfile : ProfileOf<MemberResponse>
{
    protected override void Configure()
    {
        // fetch ProvinceId from the User service
        UseDistributedKey<UserDistributedKey>()
            .Of(x => x.UserId)
            .For(x => x.ProvinceId, "ProvinceId");
 
        // fetch CountryName from the Province service
        // FxMap resolves ProvinceId (the rule above) before executing this
        UseDistributedKey<ProvinceDistributedKey>()
            .Of(x => x.ProvinceId)
            .For(x => x.CountryName, "Country.Name");
    }
}

How FxMap Resolves Dependencies

1

GraphQL query requests countryName

2

FxMap detects that CountryName depends on ProvinceId

3

Resolves ProvinceId from User service first

4

Uses the resolved ProvinceId to fetch CountryName from Province service

The client does not have to select provinceId. See dependent properties for the full pattern.

Simple Resolver Implementation

Your resolvers become incredibly simple - just return your data. FxMap handles ALL the mapping automatically:

public class Query
{
    public List<MemberResponse> GetMembers([Parameters] GetMembersParameters parameters)
    {
        // Just return your data - FxMap handles everything!
        return
        [
            .. Enumerable.Range(1, 3).Select(a => new MemberResponse
            {
                Id = a.ToString(),
                UserId = a.ToString(),
                MemberAdditionalId = a.ToString(),
                MemberSocialId = a.ToString(),
                MemberAddressId = a.ToString()
            })
        ];
    }
}

✨

Zero Mapping Code Required

Notice there's NO manual mapping, NO service injection, NO MapDataAsync calls. FxMap automatically intercepts the HotChocolate resolver and maps all profile-declared properties before returning to the GraphQL client.

GraphQL Query Example

Query only the fields you need. FxMap automatically resolves dependencies:

GraphQL Query

{
  members {
    id
    countryName
  }
}

Only requesting countryName

What FxMap Does

// FxMap automatically:
// 1. Fetches ProvinceId
//    from User service
// 2. Uses ProvinceId to fetch
//    Country.Name from
//    Province service
// 3. Returns only countryName
//    to GraphQL client

✓ Dependencies resolved automatically

Response

{
  "data": {
    "members": [
      {
        "id": "member-1",
        "countryName": "Canada"
      },
      {
        "id": "member-2",
        "countryName": "United States"
      }
    ]
  }
}

Advanced: Field-Level Mapping

You can also use FxMap in field resolvers for more granular control:

// UserLookup DTO and profile
public class UserLookup
{
    public string UserId { get; set; }
    public UserDto? User { get; set; }
}
 
public class UserLookupProfile : ProfileOf<UserLookup>
{
    protected override void Configure()
    {
        UseDistributedKey<UserDistributedKey>()
            .Of(x => x.UserId)
            .For(x => x.User, "{ Id, Name, Email }");
    }
}
 
// Use in HotChocolate's resolver pattern
public class OrderResolvers
{
    public async Task<UserDto?> GetUser(
        [Parent] OrderType order,
        [Service] IDistributedMapper mapper)
    {
        var result = new UserLookup { UserId = order.UserId };
        await mapper.MapDataAsync(result);
        return result.User;
    }
}

Performance Benefits

Automatic Batching

When mapping multiple orders, FxMap automatically batches requests to remote services. Instead of N+1 queries, you get efficient batch requests.

Request-Level Caching

FxMap caches entities within the same request, preventing duplicate fetches even across different resolvers.

Compiled Expressions

FxMap expressions are compiled at startup, ensuring blazing-fast runtime performance for GraphQL queries.

DataLoader Integration

FxMap works seamlessly with HotChocolate's DataLoader for even better performance:

// UserLookup DTO and profile (can be reused across resolvers)
public class UserLookup
{
    public string UserId { get; set; }
    public UserDto? User { get; set; }
}
 
public class UserLookupProfile : ProfileOf<UserLookup>
{
    protected override void Configure()
    {
        UseDistributedKey<UserDistributedKey>()
            .Of(x => x.UserId)
            .For(x => x.User, "{ Id, Name, Email }");
    }
}
 
public class UserDataLoader : BatchDataLoader<string, UserDto>
{
    private readonly IDistributedMapper _mapper;
 
    public UserDataLoader(
        IDistributedMapper mapper,
        IBatchScheduler batchScheduler,
        DataLoaderOptions options = null)
        : base(batchScheduler, options)
    {
        _mapper = mapper;
    }
 
    protected override async Task<IReadOnlyDictionary<string, UserDto>> LoadBatchAsync(
        IReadOnlyList<string> keys,
        CancellationToken cancellationToken)
    {
        var lookups = keys.Select(id => new UserLookup { UserId = id }).ToList();
 
        // FxMap batches all user fetches efficiently
        await _mapper.MapDataAsync(lookups);
 
        return lookups.ToDictionary(
            l => l.UserId,
            l => l.User!
        );
    }
}

Pro Tip: Selective Field Mapping

Use FxMap expressions to only fetch the fields your GraphQL query actually requests. This prevents over-fetching and improves performance.


Source: https://fxmapper.net/docs/integrations/hotchocolate/ — the website is always the most up to date version.

Clone this wiki locally