Skip to content

Commit c0fe073

Browse files
Use better status codes and response types (#90)
* Use better status codes and response types * update * reformat * update quality sort * update * Update src/GraphQL.AspNetCore3/GraphQLHttpMiddlewareOptions.cs Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --------- Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
1 parent 7cd7d06 commit c0fe073

14 files changed

+377
-62
lines changed

migration.md

Lines changed: 32 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,37 @@
11
# Version history / migration notes
22

3+
## 8.0.0
4+
5+
### New features
6+
7+
- Response content type negotiation now properly handles the `Accept` header, supporting
8+
`application/graphql-response+json`, `application/json`, and `application/graphql+json` (deprecated).
9+
- Status codes for validation errors are now, by default, determined by the response content type,
10+
and for authentication errors may return a 401 or 403 status code. These changes are pursuant
11+
to the [GraphQL over HTTP specification](https://github.com/graphql/graphql-over-http/blob/main/spec/GraphQLOverHTTP.md).
12+
See the breaking changes section below for more information.
13+
14+
### Breaking changes
15+
16+
- `GraphQLHttpMiddlewareOptions.ValidationErrorsReturnBadRequest` is now a nullable boolean where
17+
`null` means "use the default behavior". The default behavior is to return a 200 status code
18+
when the response content type is `application/json` and a 400 status code otherwise. The
19+
default value for this in v7 was `true`; set this option to retain the v7 behavior.
20+
- Validation errors such as authentication errors may now be returned with a 'preferred' status
21+
code instead of a 400 status code. This occurs when (1) the response would otherwise contain
22+
a 400 status code (e.g. the execution of the document has not yet begun), and (2) all errors
23+
in the response prefer the same status code. For practical purposes, this means that the included
24+
errors triggered by the authorization validation rule will now return 401 or 403 when appropriate.
25+
- The `SelectResponseContentType` method now returns a `MediaTypeHeaderValue` instead of a string.
26+
- The default response content type is now `application/graphql-response+json` (configurable via
27+
`GraphQLHttpMiddlewareOptions.DefaultResponseContentType`), which is the new standard per the
28+
GraphQL over HTTP specification.
29+
30+
### Other changes
31+
32+
- Added deprecation comments to `MEDIATYPE_GRAPHQLJSON` and `CONTENTTYPE_GRAPHQLJSON` constants
33+
as `application/graphql+json` is being phased out in favor of `application/graphql-response+json`.
34+
335
## 7.0.0
436

537
GraphQL.AspNetCore3 v7 requires GraphQL.NET v8 or newer.
@@ -33,10 +65,6 @@ GraphQL.AspNetCore3 v6 requires GraphQL.NET v8 or newer.
3365

3466
### Breaking changes
3567

36-
- `GraphQLHttpMiddlewareOptions.ValidationErrorsReturnBadRequest` is now a nullable boolean where
37-
`null` means "use the default behavior". The default behavior is to return a 200 status code
38-
when the response content type is `application/json` and a 400 status code otherwise. The
39-
default value for this in v7 was `true`; set this option to retain the v7 behavior.
4068
- The validation rules' signatures have changed slightly due to the underlying changes to the
4169
GraphQL.NET library. Please see the GraphQL.NET v8 migration document for more information.
4270
- Cross-site request forgery (CSRF) protection has been enabled for all requests by default.
@@ -46,12 +74,6 @@ GraphQL.AspNetCore3 v6 requires GraphQL.NET v8 or newer.
4674
the `CsrfProtectionHeaders` property on the same class. See the readme for more details.
4775
- Form POST requests are disabled by default; to enable them, set the `ReadFormOnPost` setting
4876
to `true`.
49-
- Validation errors such as authentication errors may now be returned with a 'preferred' status
50-
code instead of a 400 status code. This occurs when (1) the response would otherwise contain
51-
a 400 status code (e.g. the execution of the document has not yet begun), and (2) all errors
52-
in the response prefer the same status code. For practical purposes, this means that the included
53-
errors triggered by the authorization validation rule will now return 401 or 403 when appropriate.
54-
- The `SelectResponseContentType` method now returns a `MediaTypeHeaderValue` instead of a string.
5577
- The `AuthorizationVisitorBase.GetRecursivelyReferencedUsedFragments` method has been removed as
5678
`ValidationContext` now provides an overload to `GetRecursivelyReferencedFragments` which will only
5779
return fragments in use by the specified operation.

src/GraphQL.AspNetCore3/AuthorizationVisitorBase.Validation.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@ protected virtual void HandleNodeNotAuthorized(ValidationInfo info)
131131
{
132132
var resource = GenerateResourceDescription(info);
133133
var err = info.Node == null ? new AccessDeniedError(resource) : new AccessDeniedError(resource, info.Context.Document.Source, info.Node);
134+
err.PreferredStatusCode = HttpStatusCode.Unauthorized;
134135
info.Context.ReportError(err);
135136
}
136137

src/GraphQL.AspNetCore3/Errors/AccessDeniedError.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ namespace GraphQL.AspNetCore3.Errors;
55
/// <summary>
66
/// Represents an error indicating that the user is not allowed access to the specified resource.
77
/// </summary>
8-
public class AccessDeniedError : ValidationError
8+
public class AccessDeniedError : ValidationError, IHasPreferredStatusCode
99
{
1010
/// <inheritdoc cref="AccessDeniedError"/>
1111
public AccessDeniedError(string resource)
@@ -31,4 +31,7 @@ public AccessDeniedError(string resource, GraphQLParser.ROM originalQuery, param
3131
/// Returns the list of role memberships that would allow access to these node(s).
3232
/// </summary>
3333
public List<string>? RolesRequired { get; set; }
34+
35+
/// <inheritdoc/>
36+
public HttpStatusCode PreferredStatusCode { get; set; } = HttpStatusCode.Forbidden;
3437
}

src/GraphQL.AspNetCore3/Errors/FileCountExceededError.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,5 +14,5 @@ public FileCountExceededError()
1414
}
1515

1616
/// <inheritdoc/>
17-
public HttpStatusCode PreferredStatusCode => HttpStatusCode.RequestEntityTooLarge;
17+
public HttpStatusCode PreferredStatusCode { get; set; } = HttpStatusCode.RequestEntityTooLarge;
1818
}

src/GraphQL.AspNetCore3/Errors/FileSizeExceededError.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,5 +14,5 @@ public FileSizeExceededError()
1414
}
1515

1616
/// <inheritdoc/>
17-
public HttpStatusCode PreferredStatusCode => HttpStatusCode.RequestEntityTooLarge;
17+
public HttpStatusCode PreferredStatusCode { get; set; } = HttpStatusCode.RequestEntityTooLarge;
1818
}

src/GraphQL.AspNetCore3/Errors/HttpMethodValidationError.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,14 @@ namespace GraphQL.AspNetCore3.Errors;
44
/// Represents a validation error indicating that the requested operation is not valid
55
/// for the type of HTTP request.
66
/// </summary>
7-
public class HttpMethodValidationError : ValidationError
7+
public class HttpMethodValidationError : ValidationError, IHasPreferredStatusCode
88
{
99
/// <inheritdoc cref="HttpMethodValidationError"/>
1010
public HttpMethodValidationError(GraphQLParser.ROM originalQuery, ASTNode node, string message)
1111
: base(originalQuery, null!, message, node)
1212
{
1313
}
14+
15+
/// <inheritdoc/>
16+
public HttpStatusCode PreferredStatusCode { get; set; } = HttpStatusCode.MethodNotAllowed;
1417
}

src/GraphQL.AspNetCore3/Errors/InvalidContentTypeError.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,14 @@ namespace GraphQL.AspNetCore3.Errors;
33
/// <summary>
44
/// Represents an error indicating that the content-type was invalid.
55
/// </summary>
6-
public class InvalidContentTypeError : RequestError
6+
public class InvalidContentTypeError : RequestError, IHasPreferredStatusCode
77
{
88
/// <inheritdoc cref="InvalidContentTypeError"/>
99
public InvalidContentTypeError() : base("Invalid 'Content-Type' header.") { }
1010

1111
/// <inheritdoc cref="InvalidContentTypeError"/>
1212
public InvalidContentTypeError(string message) : base("Invalid 'Content-Type' header: " + message) { }
13+
14+
/// <inheritdoc/>
15+
public HttpStatusCode PreferredStatusCode { get; set; } = HttpStatusCode.UnsupportedMediaType;
1316
}

0 commit comments

Comments
 (0)