Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,26 @@
- per-request headers support via `Headers` property on all client options classes
- `IRequestOptions` interface and `RequestOptions` class for API-level header support
- `IClientRequestOptions` interface and `ClientRequestOptions` class for client-level header support
- add header validation to prevent overiding of reserved headers
- add header validation to prevent overriding of reserved headers
- feat: add write conflict resolution options
- `ConflictOptions` to control behavior for duplicate writes and missing deletes
- `OnDuplicateWrites` option: `Error` (default) or `Ignore` for handling duplicate tuple writes
- `OnMissingDeletes` option: `Error` (default) or `Ignore` for handling missing tuple deletes
- Available in `ClientWriteOptions.Conflict` property

[!WARNING]
BREAKING CHANGES:

- **OpenFgaApi methods**: All API methods now accept an `IRequestOptions? options` parameter. If you are using the low-level `OpenFgaApi` directly, you may need to update your calls:

Before:

```csharp
await api.Check(storeId, body, cancellationToken);
```

After:

```csharp
var options = new RequestOptions {
Headers = new Dictionary<string, string> { { "X-Custom-Header", "value" } }
Expand All @@ -30,11 +37,13 @@ BREAKING CHANGES:
- **ClientRequestOptions renamed**: The base client request options interface has been renamed from `ClientRequestOptions` to `IClientRequestOptions` to better follow .NET naming conventions. A concrete `ClientRequestOptions` class is now also available. If you were casting to or implementing this interface, update your code:

Before:

```csharp
var options = obj as ClientRequestOptions;
```

After:

```csharp
var options = obj as IClientRequestOptions;
```
Expand Down
39 changes: 39 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -574,6 +574,45 @@ var options = new ClientWriteOptions {
var response = await fgaClient.Write(body, options);
```

##### Conflict Options for Write Operations

The SDK allows you to control how write conflicts are handled using the `Conflict` option:

- **OnDuplicateWrites**: Controls behavior when writing a tuple that already exists
- `OnDuplicateWrites.Error` - Return error on duplicates (default)
- `OnDuplicateWrites.Ignore` - Silently skip duplicate writes

- **OnMissingDeletes**: Controls behavior when deleting a tuple that doesn't exist
- `OnMissingDeletes.Error` - Return error on missing deletes (default)
- `OnMissingDeletes.Ignore` - Silently skip missing deletes

```csharp
var body = new ClientWriteRequest() {
Writes = new List<ClientTupleKey> {
new() {
User = "user:81684243-9356-4421-8fbf-a4f8d36aa31b",
Relation = "viewer",
Object = "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a",
}
},
Deletes = new List<ClientTupleKeyWithoutCondition> {
new() {
User = "user:81684243-9356-4421-8fbf-a4f8d36aa31b",
Relation = "writer",
Object = "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a",
}
},
};
var options = new ClientWriteOptions {
AuthorizationModelId = "01GXSA8YR785C4FYS3C0RTG7B1",
Conflict = new ConflictOptions {
OnDuplicateWrites = OnDuplicateWrites.Ignore,
OnMissingDeletes = OnMissingDeletes.Ignore
}
};
var response = await fgaClient.Write(body, options);
```

#### Relationship Queries

##### Check
Expand Down
Loading
Loading