Skip to content

Latest commit

 

History

History
277 lines (210 loc) · 10.9 KB

migration7.md

File metadata and controls

277 lines (210 loc) · 10.9 KB

Migrating from v6 to v7.1

Major changes and new features

GraphQL Middleware

  • Configuration simplified to a single line of code
  • Single middleware to support GET, POST and WebSocket connections (configurable)
  • Media type of 'application/graphql-response+json' is returned as recommended by the draft spec (configurable)
  • Batched requests will execute in parallel within separate service scopes (configurable)
  • Authorization rules can be set on endpoints, regardless of schema configuration
  • Mutation requests are disallowed over GET connections, as required by the spec
  • Support for ASP.NET Core 2.1 and .NET Framework 4.8 has been added
  • Middleware includes several configuration options to alter the default behavior without creating a derived class
  • Configuration options can be set independently for each configured endpoint
  • New OOP design; middleware is easily extended in a derived class
  • Removed virtual method GetCancellationToken; token is pulled from HttpContext.RequestAborted
  • HttpContext.User is passed to ExecutionOptions.User so it can be accessed by validation rules and field resolvers

Subscriptions / WebSocket connections

  • WebSocket support has been moved into the main project (Transports.AspNetCore) and is included within the middleware above; no separate configuration is necessary
  • No 3rd party dependencies required (i.e. DataFlow or System.Reactive)
  • WebSocket connections now support both the graphql-ws and graphql-transport-ws protocols
  • Tighter adherence to the respective protocol, with configurable timeouts
  • Added Server-side keep-alive functionality (configurable)
  • New OOP simplified design that can easily be extended to support additional protocols
  • If a server-side error occurs via OnError, connected clients are disconnected (configurable)
  • Authorization of WebSocket connections via the ConnectionInit message is supported
  • The payload from a ConnectionInit message can be considered when building the user context
  • Requests execute within their own service scope, and when combined with ScopedSubscriptionExecutionStrategy, subscription data events can be configured to execute within their own scope as well
  • Active subscription connections are terminated when the host is shutting down

Authorization rule (new)

  • Configuration simplified to a single line of code
  • Support moved into the main project (Transports.AspNetCore); no separate NuGet reference required
  • Removed IClaimsPrincipalAccessor; ValidationContext.User is used to acquire ClaimsPrincipal reference
  • As a security fix, authorization failure messages do not reveal the authorization requirements to the caller
  • Removed IAuthorizationErrorMessageBuilder
  • Added support for AuthorizeWithRole(string role)
  • Added support for Authorize()
  • Added support for AllowAnonymous()
  • Removed support for authorization checks on all input types
  • Authorization checks are skipped for fields or fragments that should be skipped due to an @skip or @include directive

Old authorization rule

  • The authorization rule as it existed in GraphQL.NET Server v6 is still present, but marked as [Obsolete]. IClaimsPrincipalAccessor and IAuthorizationErrorMessageBuilder are still supported and messages are generated in generally the same manner as in v6.
  • Other new features, such as AuthorizeWithRole and proper @skip support are included.
  • These obsolete classes will be removed in v8; please open an issue if you require any of the deprecated features.
  • It is important to note that authorization checks on all input types are not supported even with this deprecated rule.

MVC projects

  • Added an ExecutionResultActionResult class for returning GraphQL responses from MVC controller action methods

UI middleware

  • Support for ASP.NET Core 2.1 and .NET Framework 4.8 has been added
  • Supports relative URLs for graphql and subscription endpoints
  • Supports fully-qualified URLs for graphql and subscription endpoints
  • Supports configuring RequestCredentials for Altair and GraphiQL middleware
  • Altair UI middleware supports setting WebSocket connection payload

Sample projects

Added multiple sample projects, as follows:

Name Framework Description
Authorization .NET 6 Minimal Based on the VS template, demonstrates authorization functionality with cookie-based authentication
Basic .NET 6 Minimal Simplest possible implementation
Complex .NET 3.1 / 5 / 6 Rename of existing sample server, which demonstrates older Program/Startup files and various configuration options, and multiple UI endpoints
Controller .NET 6 Minimal MVC implementation; does not include WebSocket support
Cors .NET 6 Minimal Demonstrates CORS setup
EndpointRouting .NET 6 Minimal Demonstrates configuring GraphQL through endpoint routing
MultipleSchemas .NET 6 Minimal Demonstrates configuring multiple schemas within a single server
Net48 .NET Core 2.1 / .NET 4.8 Demonstrates configuring GraphQL on .NET 4.8 / Core 2.1
Pages .NET 6 Minimal Demonstrates configuring GraphQL on top of a Razor Pages template

Testing

  • Enhanced testing of all code, reaching approximately 95%+ coverage for Transports.AspNetCore
  • Extensive testing of authorization rules

Migration of middleware

General migration notes

  1. Remove the call to AddHttpMiddleware, and if present, AddWebSockets, AddWebSocketsHttpMiddleware and UseGraphQLWebSockets.
  2. Remove the NuGet reference to GraphQL.Server.Transports.Subscriptions.WebSockets, if any. Only the GraphQL.Server.Transports.AspNetCore (or the GraphQL.Server.All) NuGet package is necessary.
// v6
services.AddGraphQL(b => b
    .AddHttpMiddleware<MySchema>()
    .AddWebSocketsHttpMiddleware<MySchema>()
    .AddWebSockets()
    // other code
);

// v7
services.AddGraphQL(b => b
    // other code
);

// v6
app.UseGraphQL<MySchema>();
app.UseGraphQLWebSockets<MySchema>();
// or
app.UseGraphQL<MySchema>("/graphql");
app.UseGraphQLWebSockets<MySchema>("/graphql");

// v7
app.UseGraphQL<MySchema>();
// or
app.UseGraphQL<MySchema>("/graphql");
// or
app.UseGraphQL();
// or
app.UseGraphQL("/graphql");

Note that the call to app.UseWebSockets() is part of ASP.NET Core and is still required for WebSocket support.

Migrating from older versions

Be sure to also remove these NuGet references in your project:

  • GraphQL.Server.Core
  • GraphQL.Server.Transports.AspNetCore.SystemTextJson
  • GraphQL.Server.Transports.AspNetCore.NewtonsoftJson

There will also be some additional changes necessary to your Startup.cs file. Please review sample projects for the current recommended configuration.

With derived middleware class

There is no clear example for rewriting derived middleware classes, as most of the virtual methods' signatures have changed. Be aware that GraphQLHttpMiddlewareOptions, or your derived options class, must be passed with the UseGraphQL method.

class MyMiddleware : GraphQLHttpMiddleware<MySchema>
{
    public MyMiddleware(
        RequestDelegate next,
        IGraphQLTextSerializer serializer,
        IDocumentExecuter<TSchema> documentExecuter,
        IServiceScopeFactory serviceScopeFactory,
        GraphQLHttpMiddlewareOptions options,
        IHostApplicationLifetime hostApplicationLifetime)
        : base(next, serializer, documentExecuter, serviceScopeFactory, options, hostApplicationLifetime)
    {
    }

    // overridden methods here
}

app.UseGraphQL<MyMiddleware>(new GraphQLHttpMiddlewareOptions());

With separate subscription endpoint

// v6
app.UseGraphQL<MySchema>("/graphql");
app.UseGraphQLWebSockets<MySchema>("/graphqlsubscription");

// v7
app.UseGraphQL<MySchema>("/graphql", o => o.HandleWebSockets = false);
app.UseGraphQL<MySchema>("/graphqlsubscription", o => {
    o.HandleGet = false;
    o.HandlePost = false;
});

To retain prior media type of `application/json`

// with no charset specified
app.UseGraphQL("/graphql", o => o.DefaultResponseContentType = new("application/json"));

// with utf-8 charset specified
app.UseGraphQL("/graphql", o => o.DefaultResponseContentType = new("application/json") { Charset = "utf-8" });

Note that if a request is received with a specific supported media type in the Accept header, such as application/graphql-response+json, then the supported media type will be returned rather than the default. Override the SelectResponseContentType method within the middleware for more precise control of the Content-Type header in the response.

If you had code within the `RequestExecutedAsync` protected method

Either override HandleRequestAsync, HandleBatchRequestAsync and/or ExecuteRequestAsync, or call the builder method ConfigureExecution to add code before/after the call to IDocumentExecuter.ExecuteAsync.

Migration of user context builder

If you used the AddUserContextBuilder builder method, there are no changes necessary. For custom implementations of IUserContextBuilder, you will need to update the method signature for BuildUserContextAsync.

Migration of authorization validation rule

⚠️ Note that authorization rules on input types are ignored in v7 ⚠️

If you need IClaimsPrincipalAccessor, IAuthorizationErrorMessageBuilder, or the detailed authorization failure messages provided in v6, then you may use the deprecated authorization rule with no code changes. Please open an issue within GitHub explaining your need so it may be addressed.

Otherwise, remove the GraphQL.Server.Authorization.AspNetCore NuGet package and make changes as shown below:

// 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
});

Use of old authorization validation rule

⚠️ Note that authorization rules on input types are ignored in v7 ⚠️

The user is checked for being authenticated before checking for the specified policy, and will return a not-authenticated failure if not authenticated, prior to any policy checks.

This allows for proper 401/403 status code responses over HTTP, if desired.

Migration of UI middleware

The path must now be specified prior to the options class, rather than after.

// v6/v7
app.UseGraphQLPlayground();

// v6/v7
app.UseGraphQLPlayground("/");

// v6
app.UseGraphQLPlayground(new PlaygroundOptions(), "/");
// v7
app.UseGraphQLPlayground("/", new PlaygroundOptions());

// v6
app.UseGraphQLPlayground(new PlaygroundOptions());
// v7
app.UseGraphQLPlayground(options: new PlaygroundOptions());