Skip to content

Commit 9d5a6ee

Browse files
authored
Merge pull request #165 from json-api-dotnet/feat/#163
feat(QueryAccessor): addGetRequired<T>(string)
2 parents d9d6f7f + 5262ee3 commit 9d5a6ee

File tree

4 files changed

+86
-21
lines changed

4 files changed

+86
-21
lines changed

src/JsonApiDotNetCore/JsonApiDotNetCore.csproj

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<Project Sdk="Microsoft.NET.Sdk">
22
<PropertyGroup>
3-
<VersionPrefix>2.1.4</VersionPrefix>
3+
<VersionPrefix>2.1.5</VersionPrefix>
44
<TargetFrameworks>netstandard1.6</TargetFrameworks>
55
<AssemblyName>JsonApiDotNetCore</AssemblyName>
66
<PackageId>JsonApiDotNetCore</PackageId>

src/JsonApiDotNetCore/Services/IQueryAccessor.cs

-9
This file was deleted.

src/JsonApiDotNetCore/Services/QueryAccessor.cs

+27-8
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,62 @@
11
using System;
2-
using System.Collections.Generic;
32
using System.Linq;
43
using JsonApiDotNetCore.Internal;
54
using Microsoft.Extensions.Logging;
65

76
namespace JsonApiDotNetCore.Services
87
{
8+
public interface IQueryAccessor
9+
{
10+
bool TryGetValue<T>(string key, out T value);
11+
12+
/// <summary>
13+
/// Gets the query value and throws a if it is not present.
14+
/// If the exception is not caught, the middleware will return an HTTP 422 response.
15+
/// </summary>
16+
/// <exception cref="JsonApiException" />
17+
T GetRequired<T>(string key);
18+
}
19+
920
public class QueryAccessor : IQueryAccessor
1021
{
1122
private readonly IJsonApiContext _jsonApiContext;
1223
private readonly ILogger<QueryAccessor> _logger;
1324

1425
public QueryAccessor(
15-
IJsonApiContext jsonApiContext,
16-
ILoggerFactory loggerFactory)
26+
IJsonApiContext jsonApiContext,
27+
ILogger<QueryAccessor> logger)
1728
{
1829
_jsonApiContext = jsonApiContext;
19-
_logger = loggerFactory.CreateLogger<QueryAccessor>();
30+
_logger = logger;
31+
}
32+
33+
public T GetRequired<T>(string key)
34+
{
35+
if (TryGetValue<T>(key, out T result) == false)
36+
throw new JsonApiException(422, $"'{key}' is not a valid '{typeof(T).Name}' value for query parameter {key}");
37+
38+
return result;
2039
}
2140

2241
public bool TryGetValue<T>(string key, out T value)
2342
{
2443
value = default(T);
2544

26-
var stringValue = GetFilterValue(key);
27-
if(stringValue == null)
45+
var stringValue = GetFilterValue(key);
46+
if (stringValue == null)
2847
{
2948
_logger.LogInformation($"'{key}' was not found in the query collection");
3049
return false;
3150
}
32-
51+
3352
try
3453
{
3554
value = TypeHelper.ConvertType<T>(stringValue);
3655
return true;
3756
}
3857
catch (FormatException)
3958
{
40-
_logger.LogInformation($"'{value}' is not a valid guid value for query parameter {key}");
59+
_logger.LogInformation($"'{value}' is not a valid '{typeof(T).Name}' value for query parameter {key}");
4160
return false;
4261
}
4362
}

test/UnitTests/Services/QueryAccessorTests.cs

+58-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System;
22
using System.Collections.Generic;
3+
using JsonApiDotNetCore.Internal;
34
using JsonApiDotNetCore.Internal.Query;
45
using JsonApiDotNetCore.Services;
56
using Microsoft.AspNetCore.Http;
@@ -13,13 +14,13 @@ namespace UnitTests.Services
1314
public class QueryAccessorTests
1415
{
1516
private readonly Mock<IJsonApiContext> _contextMock;
16-
private readonly Mock<ILoggerFactory> _loggerMock;
17+
private readonly Mock<ILogger<QueryAccessor>> _loggerMock;
1718
private readonly Mock<IQueryCollection> _queryMock;
1819

1920
public QueryAccessorTests()
2021
{
2122
_contextMock = new Mock<IJsonApiContext>();
22-
_loggerMock = new Mock<ILoggerFactory>();
23+
_loggerMock = new Mock<ILogger<QueryAccessor>>();
2324
_queryMock = new Mock<IQueryCollection>();
2425
}
2526

@@ -34,7 +35,7 @@ public void Can_Get_Guid_QueryValue()
3435
var query = new Dictionary<string, StringValues> {
3536
{ filterQuery, value.ToString() }
3637
};
37-
38+
3839
_queryMock.Setup(q => q.GetEnumerator()).Returns(query.GetEnumerator());
3940

4041
var querySet = new QuerySet(_contextMock.Object, _queryMock.Object);
@@ -50,5 +51,59 @@ public void Can_Get_Guid_QueryValue()
5051
Assert.True(success);
5152
Assert.Equal(value, result);
5253
}
54+
55+
[Fact]
56+
public void GetRequired_Throws_If_Not_Present()
57+
{
58+
// arrange
59+
const string key = "some-id";
60+
var filterQuery = $"filter[{key}]";
61+
var value = Guid.NewGuid();
62+
63+
var query = new Dictionary<string, StringValues> {
64+
{ filterQuery, value.ToString() }
65+
};
66+
67+
_queryMock.Setup(q => q.GetEnumerator()).Returns(query.GetEnumerator());
68+
69+
var querySet = new QuerySet(_contextMock.Object, _queryMock.Object);
70+
_contextMock.Setup(c => c.QuerySet)
71+
.Returns(querySet);
72+
73+
var service = new QueryAccessor(_contextMock.Object, _loggerMock.Object);
74+
75+
// act
76+
var exception = Assert.Throws<JsonApiException>(() => service.GetRequired<Guid>("Invalid"));
77+
78+
// assert
79+
Assert.Equal(422, exception.GetStatusCode());
80+
}
81+
82+
[Fact]
83+
public void GetRequired_Does_Not_Throw_If_Present()
84+
{
85+
// arrange
86+
const string key = "some-id";
87+
var filterQuery = $"filter[{key}]";
88+
var value = Guid.NewGuid();
89+
90+
var query = new Dictionary<string, StringValues> {
91+
{ filterQuery, value.ToString() }
92+
};
93+
94+
_queryMock.Setup(q => q.GetEnumerator()).Returns(query.GetEnumerator());
95+
96+
var querySet = new QuerySet(_contextMock.Object, _queryMock.Object);
97+
_contextMock.Setup(c => c.QuerySet)
98+
.Returns(querySet);
99+
100+
var service = new QueryAccessor(_contextMock.Object, _loggerMock.Object);
101+
102+
// act
103+
var result = service.GetRequired<Guid>("SomeId");
104+
105+
// assert
106+
Assert.Equal(value, result);
107+
}
53108
}
54109
}

0 commit comments

Comments
 (0)