Skip to content

Conversation

@samyonr
Copy link
Contributor

@samyonr samyonr commented Jun 18, 2025

Problem

When using HttpClient.PostAsJsonAsync() to call the GraphQL endpoint (EntityGraphQLEndpointRouteExtensions.MapGraphQL), the request fails with 400 Bad Request. This happens because PostAsJsonAsync:

  • Sets Transfer-Encoding: chunked
  • Does not set Content-Length

The current implementation in EntityGraphQLEndpointRouteExtensions.MapGraphQL<T>() rejects all requests where ContentLength == null or 0, making it incompatible with chunked transfers — despite chunked encoding being fully compliant with HTTP/1.1.

This behavior makes the GraphQL endpoint incompatible with a common usage of HTTP client libraries.


Fix

In MapGraphQL<TQueryType>, we now:

  • Check for Transfer-Encoding: chunked
  • If the request is chunked, we no longer reject it for having no Content-Length

This ensures the GraphQL endpoint accepts another valid type of HTTP/1.1 requests.

var isChunked = context.Request.Headers.TransferEncoding
    .Any(h => h is not null && h.Equals("chunked", StringComparison.OrdinalIgnoreCase));

if (!isChunked && (context.Request.ContentLength == null || context.Request.ContentLength == 0))
{
    context.Response.StatusCode = StatusCodes.Status400BadRequest;
    return;
}

Test Coverage

A new integration test using the existing CustomWebApplicationFactory infrastructure has been added. It runs the app over a real TCP socket (Kestrel) to confirm that:

  • PostAsJsonAsync() sends a chunked request
  • The endpoint accepts and successfully executes the GraphQL query

Note: the test must use communication over the wire, via CustomWebApplicationFactory, a Testcontainer, or any other way that's not pure in-memory, like with IClassFixture<WebApplicationFactory<Program>>. Otherwise, Content-Length is set. I've also tried to reproduce it with the .NET 10 Preview 4 feature "Use WebApplicationFactory with Kestrel for integration testing" but the test passed similar to the way it passes with IClassFixture<WebApplicationFactory<Program>>, so it wasn't a good way to reproduce it with that method:

    [Fact]
    public async Task GraphQl_Endpoint_Works_With_Kestrel()
    {
        using var factory = new WebApplicationFactory<Program>();

        factory.UseKestrel();     // <- new in .NET 10 preview
        factory.StartServer();    // <- new in .NET 10 preview

        using var client = factory.CreateClient();
        var resp = await client.PostAsJsonAsync("/graphql", new { query = "{ hello }" });
        resp.EnsureSuccessStatusCode();

        var json = await resp.Content.ReadAsStringAsync();
        Assert.Contains("\"hello\":\"world\"", json);

Result

  • Fixes: chunked payloads being rejected with 400
  • Supports: improved compliance with the GraphQL over HTTP spec
  • Supports: PostAsJsonAsync

…chunked HTTP requests sent by PostAsJsonAsync

`PostAsJsonAsync` uses `Transfer-Encoding: chunked`, which causes `ContentLength` to be `null`.
The previous GraphQL endpoint implementation rejected such requests with 400 Bad Request
if `ContentLength` was null or zero, even though chunked requests are valid per HTTP/1.1.

This change adds support for chunked requests by checking the `Transfer-Encoding` header
before applying the `ContentLength` fallback logic.

The issue is reproduced with `GraphQL_Endpoint_200_On_Chunked_Data_Query` test,
that uses `CustomWebApplicationFactory` (won't work with `IClassFixture<WebApplicationFactory<Program>>`
because it must communicate over the wire).
@lukemurray lukemurray merged commit fe9fb37 into EntityGraphQL:master Aug 6, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants