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
1 change: 1 addition & 0 deletions .openapi-generator/FILES
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,7 @@ model_write_authorization_model_response.go
model_write_request.go
model_write_request_deletes.go
model_write_request_writes.go
models_test.go
oauth2/LICENSE
oauth2/ORIGINAL_AUTHORS
oauth2/ORIGINAL_CONTRIBUTORS
Expand Down
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
## [Unreleased](https://github.com/openfga/go-sdk/compare/v0.7.2...HEAD)

- feat: add support for custom headers per request. See [documentation](https://github.com/openfga/go-sdk#custom-headers).
- feat: add support for conflict options for Write operations**: (#229)
The client now supports setting `Conflict` on `ClientWriteOptions` to control behavior when writing duplicate tuples or deleting non-existent tuples. This feature requires OpenFGA server [v1.10.0](https://github.com/openfga/openfga/releases/tag/v1.10.0) or later.
See [Conflict Options for Write Operations](./README.md#conflict-options-for-write-operations) for more.

## 0.7.2

Expand Down
36 changes: 36 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -680,6 +680,42 @@ data, err := fgaClient.Write(context.Background()).Body(body).Options(options).E
// }]
```

#### Conflict Options for Write Operations

The SDK supports conflict options for write operations, allowing you to control how the API handles duplicate writes and missing deletes.

> Note: This requires OpenFGA [v1.10.0](https://github.com/openfga/openfga/releases/tag/v1.10.0) or later.

```go
options := ClientWriteOptions{
Conflict: ClientWriteConflictOptions{
// Control what happens when writing a tuple that already exists
OnDuplicateWrites: CLIENT_WRITE_REQUEST_ON_DUPLICATE_WRITES_IGNORE, // or CLIENT_WRITE_REQUEST_ON_DUPLICATE_WRITES_ERROR (the current default behavior)

// Control what happens when deleting a tuple that doesn't exist
OnMissingDeletes: CLIENT_WRITE_REQUEST_ON_MISSING_DELETES_IGNORE, // or CLIENT_WRITE_REQUEST_ON_MISSING_DELETES_ERROR (the current default behavior)
},
}

body := ClientWriteRequest{
Writes: []ClientTupleKey{ {
User: "user:anne",
Relation: "writer",
Object: "document:2021-budget",
} },
Deletes: []ClientTupleKeyWithoutCondition{ {
User: "user:bob",
Relation: "reader",
Object: "document:2021-budget",
} },
}

data, err := fgaClient.Write(context.Background()).
Body(body).
Options(options).
Execute()
```

#### Relationship Queries

##### Check
Expand Down
22 changes: 16 additions & 6 deletions api_open_fga.go
Original file line number Diff line number Diff line change
Expand Up @@ -775,7 +775,10 @@ type OpenFgaApi interface {
* Write Add or delete tuples from the store
* The Write API will transactionally update the tuples for a certain store. Tuples and type definitions allow OpenFGA to determine whether a relationship exists between an object and an user.
In the body, `writes` adds new tuples and `deletes` removes existing tuples. When deleting a tuple, any `condition` specified with it is ignored.
The API is not idempotent: if, later on, you try to add the same tuple key (even if the `condition` is different), or if you try to delete a non-existing tuple, it will throw an error.
The API is not idempotent by default: if, later on, you try to add the same tuple key (even if the `condition` is different), or if you try to delete a non-existing tuple, it will throw an error.
To allow writes when an identical tuple already exists in the database, set `"on_duplicate": "ignore"` on the `writes` object.
To allow deletes when a tuple was already removed from the database, set `"on_missing": "ignore"` on the `deletes` object.
If a Write request contains both idempotent (ignore) and non-idempotent (error) operations, the most restrictive action (error) will take precedence. If a condition fails for a sub-request with an error flag, the entire transaction will be rolled back. This gives developers explicit control over the atomicity of the requests.
Comment thread
rhamzeh marked this conversation as resolved.
The API will not allow you to write tuples such as `document:2021-budget#viewer@document:2021-budget#viewer`, because they are implicit.
An `authorization_model_id` may be specified in the body. If it is, it will be used to assert that each written tuple (not deleted) is valid for the model specified. If it is not specified, the latest authorization model ID will be used.
## Example
Expand All @@ -790,7 +793,8 @@ type OpenFgaApi interface {
"relation": "writer",
"object": "document:2021-budget"
}
]
],
"on_duplicate": "ignore"
},
"authorization_model_id": "01G50QVV17PECNVAHX1GG4Y5NC"
}
Expand All @@ -806,7 +810,8 @@ type OpenFgaApi interface {
"relation": "reader",
"object": "document:2021-budget"
}
]
],
"on_missing": "ignore"
}
}
```
Expand Down Expand Up @@ -4192,7 +4197,10 @@ func (r ApiWriteRequest) Execute() (map[string]interface{}, *http.Response, erro
- The Write API will transactionally update the tuples for a certain store. Tuples and type definitions allow OpenFGA to determine whether a relationship exists between an object and an user.

In the body, `writes` adds new tuples and `deletes` removes existing tuples. When deleting a tuple, any `condition` specified with it is ignored.
The API is not idempotent: if, later on, you try to add the same tuple key (even if the `condition` is different), or if you try to delete a non-existing tuple, it will throw an error.
The API is not idempotent by default: if, later on, you try to add the same tuple key (even if the `condition` is different), or if you try to delete a non-existing tuple, it will throw an error.
To allow writes when an identical tuple already exists in the database, set `"on_duplicate": "ignore"` on the `writes` object.
To allow deletes when a tuple was already removed from the database, set `"on_missing": "ignore"` on the `deletes` object.
If a Write request contains both idempotent (ignore) and non-idempotent (error) operations, the most restrictive action (error) will take precedence. If a condition fails for a sub-request with an error flag, the entire transaction will be rolled back. This gives developers explicit control over the atomicity of the requests.
Comment thread
rhamzeh marked this conversation as resolved.
The API will not allow you to write tuples such as `document:2021-budget#viewer@document:2021-budget#viewer`, because they are implicit.
An `authorization_model_id` may be specified in the body. If it is, it will be used to assert that each written tuple (not deleted) is valid for the model specified. If it is not specified, the latest authorization model ID will be used.
## Example
Expand All @@ -4208,7 +4216,8 @@ To add `user:anne` as a `writer` for `document:2021-budget`, call write API with
"relation": "writer",
"object": "document:2021-budget"
}
]
],
"on_duplicate": "ignore"
},
"authorization_model_id": "01G50QVV17PECNVAHX1GG4Y5NC"
}
Expand All @@ -4226,7 +4235,8 @@ To remove `user:bob` as a `reader` for `document:2021-budget`, call write API wi
"relation": "reader",
"object": "document:2021-budget"
}
]
],
"on_missing": "ignore"
}
}

Expand Down
Loading
Loading