diff --git a/src/OpenFga.Sdk.Test/Api/OpenFgaApiTests.cs b/src/OpenFga.Sdk.Test/Api/OpenFgaApiTests.cs
index 561928d..bc3820a 100644
--- a/src/OpenFga.Sdk.Test/Api/OpenFgaApiTests.cs
+++ b/src/OpenFga.Sdk.Test/Api/OpenFgaApiTests.cs
@@ -1373,6 +1373,50 @@ public async Task ReadTest() {
Assert.Equal(response, expectedResponse);
}
+ ///
+ /// Test Read With Empty Parameters
+ ///
+ [Fact]
+ public async Task ReadEmptyTest() {
+ var mockHandler = new Mock(MockBehavior.Strict);
+ var expectedResponse = new ReadResponse() {
+ Tuples = new List() {
+ new(new TupleKey("document:roadmap", "viewer", "user:81684243-9356-4421-8fbf-a4f8d36aa31b"), DateTime.Now)
+ }
+ };
+ mockHandler.Protected()
+ .Setup>(
+ "SendAsync",
+ ItExpr.Is(req =>
+ req.RequestUri == new Uri($"{_config.BasePath}/stores/{_config.StoreId}/read") &&
+ req.Method == HttpMethod.Post),
+ ItExpr.IsAny()
+ )
+ .ReturnsAsync(new HttpResponseMessage() {
+ StatusCode = HttpStatusCode.OK,
+ Content = Utils.CreateJsonStringContent(expectedResponse),
+ });
+
+ var httpClient = new HttpClient(mockHandler.Object);
+ var openFgaApi = new OpenFgaApi(_config, httpClient);
+
+ var body = new ReadRequest { };
+ var response = await openFgaApi.Read(body);
+
+ mockHandler.Protected().Verify(
+ "SendAsync",
+ Times.Exactly(1),
+ ItExpr.Is(req =>
+ req.RequestUri == new Uri($"{_config.BasePath}/stores/{_config.StoreId}/read") &&
+ req.Method == HttpMethod.Post),
+ ItExpr.IsAny()
+ );
+
+ Assert.IsType(response);
+ Assert.Single(response.Tuples);
+ Assert.Equal(response, expectedResponse);
+ }
+
///
/// Test ReadChanges
///
diff --git a/src/OpenFga.Sdk.Test/Client/OpenFgaClientTests.cs b/src/OpenFga.Sdk.Test/Client/OpenFgaClientTests.cs
index 5505e2d..9a416ee 100644
--- a/src/OpenFga.Sdk.Test/Client/OpenFgaClientTests.cs
+++ b/src/OpenFga.Sdk.Test/Client/OpenFgaClientTests.cs
@@ -608,7 +608,8 @@ public async Task ReadTest() {
"SendAsync",
ItExpr.Is(req =>
req.RequestUri == new Uri($"{_config.BasePath}/stores/{_config.StoreId}/read") &&
- req.Method == HttpMethod.Post),
+ req.Method == HttpMethod.Post &&
+ req.Content.ReadAsStringAsync().Result.Contains("tuple")),
ItExpr.IsAny()
)
.ReturnsAsync(new HttpResponseMessage() {
@@ -632,7 +633,56 @@ public async Task ReadTest() {
Times.Exactly(1),
ItExpr.Is(req =>
req.RequestUri == new Uri($"{_config.BasePath}/stores/{_config.StoreId}/read") &&
- req.Method == HttpMethod.Post),
+ req.Method == HttpMethod.Post &&
+ req.Content.ReadAsStringAsync().Result.Contains("tuple")),
+ ItExpr.IsAny()
+ );
+
+ Assert.IsType(response);
+ Assert.Single(response.Tuples);
+ Assert.Equal(response, expectedResponse);
+ }
+
+ ///
+ /// Test Read with Empty Body
+ ///
+ [Fact]
+ public async Task ReadEmptyTest() {
+ var mockHandler = new Mock(MockBehavior.Strict);
+ var expectedResponse = new ReadResponse() {
+ Tuples = new List() {
+ new(new TupleKey("document:roadmap", "viewer", "user:81684243-9356-4421-8fbf-a4f8d36aa31b"),
+ DateTime.Now)
+ }
+ };
+ mockHandler.Protected()
+ .Setup>(
+ "SendAsync",
+ ItExpr.Is(req =>
+ req.RequestUri == new Uri($"{_config.BasePath}/stores/{_config.StoreId}/read") &&
+ req.Method == HttpMethod.Post &&
+ !req.Content.ReadAsStringAsync().Result.Contains("tuple")),
+ ItExpr.IsAny()
+ )
+ .ReturnsAsync(new HttpResponseMessage() {
+ StatusCode = HttpStatusCode.OK,
+ Content = Utils.CreateJsonStringContent(expectedResponse),
+ });
+
+ var httpClient = new HttpClient(mockHandler.Object);
+ var fgaClient = new OpenFgaClient(_config, httpClient);
+
+ var body = new ClientReadRequest() { };
+ var options = new ClientReadOptions { };
+ var response = await fgaClient.Read(body, options);
+
+ mockHandler.Protected().Verify(
+ "SendAsync",
+ Times.Exactly(1),
+ ItExpr.Is(req =>
+ req.RequestUri == new Uri($"{_config.BasePath}/stores/{_config.StoreId}/read") &&
+ req.Method == HttpMethod.Post &&
+ !req.Content.ReadAsStringAsync().Result.Contains("tuple")),
ItExpr.IsAny()
);
diff --git a/src/OpenFga.Sdk/Client/Client.cs b/src/OpenFga.Sdk/Client/Client.cs
index 686d84c..7b6cf88 100644
--- a/src/OpenFga.Sdk/Client/Client.cs
+++ b/src/OpenFga.Sdk/Client/Client.cs
@@ -148,13 +148,18 @@ public async Task ReadChanges(ClientReadChangesRequest body
* Read - Read tuples previously written to the store (does not evaluate)
*/
public async Task Read(ClientReadRequest body, IClientReadOptions? options = default,
- CancellationToken cancellationToken = default) =>
- await api.Read(
+ CancellationToken cancellationToken = default) {
+ TupleKey tupleKey = null;
+ if (body != null && (body.User != null || body.Relation != null || body.Object != null)) {
+ tupleKey = body;
+ }
+ return await api.Read(
new ReadRequest {
- TupleKey = body,
+ TupleKey = tupleKey,
PageSize = options?.PageSize,
ContinuationToken = options?.ContinuationToken
}, cancellationToken);
+ }
/**
* Write - Create or delete relationship tuples