From f1a5bf85aa45eb2ad2ed12fbcc3db425e999e3b0 Mon Sep 17 00:00:00 2001 From: Mikolaj Date: Mon, 8 May 2023 08:56:53 +0200 Subject: [PATCH] Improve default IsValidResponseToDeserialize implementation (#560) * change default implementation of response validation method to ensure correct response content type * add tests for the default validation method * remove unnecessary comments Co-authored-by: Ivan Maximov * accepted response types private, formatting * make DefaultIsValidResponseToDeserialize publicly accessible Co-authored-by: Ivan Maximov * AcceptedResponseContentTypes as static field --------- Co-authored-by: Ivan Maximov --- .../GraphQLHttpClientOptions.cs | 14 ++++++++-- .../DefaultValidationTest.cs | 28 +++++++++++++++++++ 2 files changed, 39 insertions(+), 3 deletions(-) create mode 100644 tests/GraphQL.Client.Serializer.Tests/DefaultValidationTest.cs diff --git a/src/GraphQL.Client/GraphQLHttpClientOptions.cs b/src/GraphQL.Client/GraphQLHttpClientOptions.cs index 13a9c576..169260f0 100644 --- a/src/GraphQL.Client/GraphQLHttpClientOptions.cs +++ b/src/GraphQL.Client/GraphQLHttpClientOptions.cs @@ -61,9 +61,17 @@ public class GraphQLHttpClientOptions /// Note that compatible to the draft graphql-over-http spec GraphQL Server MAY return 4xx status codes (401/403, etc.) /// with well-formed GraphQL response containing errors collection. /// - public Func IsValidResponseToDeserialize { get; set; } = r => - // Why not application/json? See https://github.com/graphql/graphql-over-http/blob/main/spec/GraphQLOverHTTP.md#processing-the-response - r.IsSuccessStatusCode || r.StatusCode == HttpStatusCode.BadRequest || r.Content.Headers.ContentType?.MediaType == "application/graphql+json"; + public Func IsValidResponseToDeserialize { get; set; } = DefaultIsValidResponseToDeserialize; + + private static readonly IReadOnlyCollection _acceptedResponseContentTypes = new[] { "application/graphql+json", "application/json", "application/graphql-response+json" }; + + public static bool DefaultIsValidResponseToDeserialize(HttpResponseMessage r) + { + if (r.Content.Headers.ContentType?.MediaType != null && !_acceptedResponseContentTypes.Contains(r.Content.Headers.ContentType.MediaType)) + return false; + + return r.IsSuccessStatusCode || r.StatusCode == HttpStatusCode.BadRequest; + } /// /// This callback is called after successfully establishing a websocket connection but before any regular request is made. diff --git a/tests/GraphQL.Client.Serializer.Tests/DefaultValidationTest.cs b/tests/GraphQL.Client.Serializer.Tests/DefaultValidationTest.cs new file mode 100644 index 00000000..861b59b6 --- /dev/null +++ b/tests/GraphQL.Client.Serializer.Tests/DefaultValidationTest.cs @@ -0,0 +1,28 @@ +using System.Net; +using System.Net.Http.Headers; +using FluentAssertions; +using GraphQL.Client.Http; +using Xunit; + +namespace GraphQL.Client.Serializer.Tests; + +public class DefaultValidationTest +{ + [Theory] + [InlineData(HttpStatusCode.OK, "application/json", true)] + [InlineData(HttpStatusCode.OK, "application/graphql-response+json", true)] + [InlineData(HttpStatusCode.BadRequest, "application/json", true)] + [InlineData(HttpStatusCode.BadRequest, "text/html", false)] + [InlineData(HttpStatusCode.OK, "text/html", false)] + [InlineData(HttpStatusCode.Forbidden, "text/html", false)] + [InlineData(HttpStatusCode.Forbidden, "application/json", false)] + public void IsValidResponse_OkJson_True(HttpStatusCode statusCode, string mediaType, bool expectedResult) + { + var response = new HttpResponseMessage(statusCode); + response.Content.Headers.ContentType = new MediaTypeHeaderValue(mediaType); + + bool isValid = new GraphQLHttpClientOptions().IsValidResponseToDeserialize(response); + + isValid.Should().Be(expectedResult); + } +}