graphql-dotnet-server

repository·master·Indexed 20 days ago

https://github.com/graphql-dotnet/server

An ASP.NET Core GraphQL server implementation built on top of GraphQL.NET. It provides support for HTTP and WebSocket transports, including subscriptions and multipart file uploads. The server integrates into ASP.NET Core via middleware, route handlers, or MVC controllers and supports various UI middleware such as Altair, GraphiQL, and Voyager.

Tokens
9.5K
Snippets
29
Records
38
Agent score
67%

What's inside graphql-dotnet-server

  1. Configure GraphQL execution in ASP.NET Core

    master

    The server can be integrated into the ASP.NET Core pipeline using several different patterns:

    1. Middleware: Configure via IApplicationBuilder or IEndpointRouteBuilder to serve requests as middleware.
    2. Route Handlers: Use .NET 6+ route handlers (e.g., MapGet, MapPost) by returning specific result types:
      • GraphQLExecutionHttpResult: For direct GraphQL execution.
      • ExecutionResultHttpResult: For returning pre-executed GraphQL responses.
    3. MVC Controllers: Return GraphQL responses from controller actions using:
      • GraphQLExecutionActionResult
      • ExecutionResultActionResult

    Authorization Support

    Includes AuthorizationValidationRule which validates that the schema, output graph types, fields, and query arguments meet the policies or roles defined in the ASP.NET Core authorization framework.

    Note: It does not validate policies/roles for input graph types, input fields, or directives. It skips validation for fields/fragments marked with @skip or @include.

  2. Supported GraphQL transport protocols

    master

    The ASP.NET Core GraphQL server supports multiple request types and protocols:

    HTTP Transport

    Compatible with the GraphQL over HTTP draft specification.

    • GET: Processes requests from the query string.
    • POST: Supports JSON requests, form submissions, and raw GraphQL strings.
    • Multipart Requests: Supports the GraphQL multipart request spec for file uploads via operations and map parameters.

    WebSocket Transport

    Supports GraphQL subscriptions via the following protocols:

    All message formats are JSON-based.

  3. Understand User Context Builder lifecycle and scope

    master

    The user context builder is executed once within the DI service scope of the original HTTP request.

    • Batched Requests: The same user context instance is passed to each GraphQL execution.
    • WebSocket Requests: The same user context instance is passed to each subscription and data event resolver execution.

    Warning: Do not create objects within the user context that rely on having the same DI service scope as the field resolvers. Because WebSocket connections are long-lived, any scoped services used within a user context builder will effectively have a long lifetime. To avoid this, you may create a temporary service scope manually within your user context builder.

    For applications with multiple schemas, you can register IUserContextBuilder<TSchema> to create a context specific to a particular schema.

  4. Configure Authorization for GraphQL

    master

    Authorization can be configured at the endpoint level or for individual graph types, fields, and arguments.

    Endpoint Authorization

    Checks authorization requirements for the entire endpoint (including introspection) before parsing or executing the document. Configure this via the UseGraphQL options delegate.

    Field and Type Authorization

    To enable ASP.NET Core authorization validation for individual fields/types, call .AddAuthorizationRule() during GraphQL service configuration. You can then use .Authorize() or the [Authorize] attribute on schema elements.

    Note: Authorization rules do not apply to input types or fields of input types.

    // Endpoint authorization
    app.UseGraphQL("/graphql", config =>
    {
        config.AuthorizationRequired = true;
        config.AuthorizedRoles.Add("MyRole");
        config.AuthorizedPolicy = "MyPolicy";
    });
    
    // Field/Type authorization
    builder.Services.AddGraphQL(b => b
        .AddAutoSchema<Query>()
        .AddSystemTextJson()
        .AddAuthorizationRule());
  5. Migrate Authorization rules from v6 to v7

    master

    v7 introduces a new, simplified authorization system integrated into Transports.AspNetCore.

    Warning: Authorization rules on input types are ignored in v7.

    Migration Steps:

    1. Remove the GraphQL.Server.Authorization.AspNetCore NuGet package.
    2. Replace .AddGraphQLAuthorization(...) with .AddAuthorizationRule() in your service configuration.
    3. Use standard ASP.NET Core services.AddAuthorization(...) for your policy configuration.

    New Authorization Features:

    • Authorize()
    • AuthorizeWithRole(string role)
    • AllowAnonymous()
    • Security fix: Authorization failure messages no longer reveal specific requirements to the caller.
    // v6
    services.AddGraphQL(b => b
        .AddGraphQLAuthorization(options => {
            // ASP.NET authorization configuration
        })
        // other code
    );
    
    // v7
    services.AddGraphQL(b => b
        .AddAuthorizationRule()
        // other code
    );
    services.AddAuthorization(options => {
        // ASP.NET authorization configuration
    });
  6. Configure GraphQL with Azure Functions

    master

    To host GraphQL in Azure Functions:

    1. Enable Dependency Injection in your Azure Function.
    2. Register GraphQL services using builder.Services.AddGraphQL().
    3. Create an HTTP function that returns GraphQLExecutionActionResult.
    4. (Optional) Add a UI function returning GraphiQLActionResult.

    Limitations:

    • Subscriptions are not supported because Azure Functions do not support WebSockets.
    • The GraphQL schema is re-initialized on every call due to the serverless environment, which may impact performance for expensive schemas.
    [FunctionName("GraphQL")]
    public static IActionResult RunGraphQL(
        [HttpTrigger(AuthorizationLevel.Anonymous, "get", "post"] HttpRequest req)
    {
        return new GraphQLExecutionActionResult();
    }
  7. Configure different authorization settings for different transports

    master

    You can register the same endpoint multiple times to apply different authorization rules to different HTTP methods (e.g., allowing GET for queries but requiring authentication for POST/WebSockets).

    Note: It is recommended to instead use the AddAuthorizationRule() and apply authorization metadata directly to your schema's Mutation and Subscription parts to avoid complexity.

    Example of transport-specific configuration:

    var app = builder.Build();
    app.UseDeveloperExceptionPage();
    // Allow unauthenticated GET requests
    app.UseGraphQL("/graphql", options =>
    {
        options.HandleGet = true;
        options.HandlePost = false;
        options.HandleWebSockets = false;
        options.AuthorizationRequired = false;
    });
    // Require authentication for POST and WebSockets
    app.UseGraphQL("/graphql", options =>
    {
        options.HandleGet = false;
        options.HandlePost = true;
        options.HandleWebSockets = true;
        options.AuthorizationRequired = true;
    });
    await app.RunAsync();
  8. Configure WebSocket keep-alive packets

    master

    By default, the middleware does not send keep-alive packets. To prevent clients from being disconnected by the OS or network due to inactivity, configure KeepAliveTimeout and KeepAliveMode in GraphQLWebSocketOptions.

    For the graphql-transport-ws sub-protocol, you can choose from several KeepAliveMode values:

    • Default: Same as Timeout.
    • Timeout: Sends a unidirectional keep-alive message when no message has been received within the specified timeout period.
    • Interval: Sends a unidirectional keep-alive message at a fixed interval.
    • TimeoutWithPayload: Sends a bidirectional keep-alive message with a payload on a fixed interval. This is useful for high-traffic servers to ensure the client is still processing messages.

    Example configuration:

    app.UseGraphQL("/graphql", options =>
    {
        // configure keep-alive packets
        options.WebSockets.KeepAliveTimeout = TimeSpan.FromSeconds(10);
        options.WebSockets.KeepAliveMode = KeepAliveMode.TimeoutWithPayload;
        // enforce the graphql-transport-ws sub-protocol
        options.WebSockets.SupportedWebSocketSubProtocols = [GraphQLWs.SubscriptionServer.SubProtocol];
    });
  9. Configure GraphQL with endpoint routing

    master

    If you are using ASP.NET Core endpoint routing, use MapGraphQL inside the UseEndpoints configuration instead of UseGraphQL on the application builder. This is useful for applying specific CORS policies to the GraphQL endpoint.

    Note on UI and WebSockets: When using endpoint routing, you cannot use WebSocket connections if a UI package is configured at the same URL. Use different URLs for the UI and the GraphQL endpoint to avoid issues.

    var app = builder.Build();
    app.UseDeveloperExceptionPage();
    app.UseWebSockets();
    app.UseRouting();
    app.UseEndpoints(endpoints =>
    {
        endpoints.MapGraphQL("graphql");
        endpoints.MapGraphQLVoyager("ui/voyager");
    });
    await app.RunAsync();
  10. Configure Response Compression for GraphQL

    master

    To enable compression for GraphQL responses, you must add the application/graphql-response+json MIME type to the ASP.NET Core response compression options.

    Warning: Enabling compression over HTTPS can expose your application to CRIME and BREACH attacks if you rely on cookies for authentication.

    builder.Services.AddResponseCompression(options =>
    {
        options.EnableForHttps = true;
        options.MimeTypes = ResponseCompressionDefaults.MimeTypes.Append("application/graphql-response+json");
    });
    
    app.UseResponseCompression();
  11. Migrate UI middleware (Playground) to v7

    master

    When migrating UI middleware like UseGraphQLPlayground, the argument order for the path and options has changed. The path must now be specified before the options class.

    // v6/v7 (if no options provided)
    app.UseGraphQLPlayground();
    
    // v6/v7 (with path)
    app.UseGraphQLPlayground("/");
    
    // v6 (options first, then path)
    app.UseGraphQLPlayground(new PlaygroundOptions(), "/");
    
    // v7 (path first, then options)
    app.UseGraphQLPlayground("/", new PlaygroundOptions());
  12. Configure GraphQL with route handlers (.NET 6+)

    master

    You can use Minimal APIs (MapGet and MapPost) to execute GraphQL requests without using UseGraphQL or MapGraphQL.

    Important: You must map MapGet to support WebSocket connections, as they upgrade from HTTP GET requests.

    // Using GraphQLExecutionHttpResult
    app.MapGet("/graphql", () => new GraphQLExecutionHttpResult());
    app.MapPost("/graphql", () => new GraphQLExecutionHttpResult());