Skip to content

Commit 4d0b80e

Browse files
authored
Add Duplicate Writes documentation (#1105)
1 parent db0dd24 commit 4d0b80e

9 files changed

Lines changed: 163 additions & 288 deletions

File tree

docs/README.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,6 @@ It offers an HTTP API, a gRPC API, and has SDKs for programming languages includ
7272
- [Manage Group Access](./content/interacting/managing-user-access.mdx)
7373
- [Manage Group Membership](./content/interacting/managing-group-membership.mdx)
7474
- [Manage Relationships Between Objects](./content/interacting/managing-relationships-between-objects.mdx)
75-
- [Transactional Writes](./content/interacting/transactional-writes.mdx)
7675
- [Relationship Queries](./content/interacting/relationship-queries.mdx)
7776
- [Get Tuple Changes](./content/interacting/read-tuple-changes.mdx)
7877
- [Search with Permissions](./content/interacting/search-with-permissions.mdx)

docs/content/getting-started/perform-check.mdx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -144,11 +144,11 @@ To obtain the [access token](https://auth0.com/docs/get-started/authentication-a
144144

145145
### 02. Calling Check API
146146

147-
To check whether user `user:anne` has relationship `can_view` with object `document:Z`
147+
To check whether user `user:anne` has relationship `reader` with object `document:Z`
148148

149149
<CheckRequestViewer
150150
user={'user:anne'}
151-
relation={'can_view'}
151+
relation={'reader'}
152152
object={'document:Z'}
153153
allowed={true}
154154
skipSetup={true}

docs/content/getting-started/update-tuples.mdx

Lines changed: 108 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
title: Update Relationship Tuples
33
sidebar_position: 3
44
slug: /getting-started/update-tuples
5-
description: Updating system state by writing and deleting relationship tuples
5+
description: Introduction to adding and deleting relationship tuples
66
---
77

88
import {
@@ -24,7 +24,7 @@ import TabItem from '@theme/TabItem';
2424

2525
<DocumentationNotice />
2626

27-
This section will illustrate how to update _<ProductConcept section="what-is-a-relationship-tuple" linkName="relationship tuples" />_.
27+
This is an introduction to adding and deleting _<ProductConcept section="what-is-a-relationship-tuple" linkName="relationship tuples" />_.
2828

2929
## Before you start
3030

@@ -93,7 +93,7 @@ Assume that you want to add user `user:anne` to have relationship `reader` with
9393
{
9494
user: 'user:anne',
9595
relation: 'reader',
96-
object: 'document:Z',
96+
object: 'document:Z'
9797
}
9898
```
9999

@@ -150,7 +150,7 @@ To add the relationship tuples, we can invoke the write API.
150150
{
151151
user: 'user:anne',
152152
relation: 'reader',
153-
object: 'document:Z',
153+
object: 'document:Z'
154154
},
155155
]}
156156
skipSetup={true}
@@ -175,7 +175,7 @@ Assume that you want to delete user `user:anne`'s `reader` relationship with obj
175175
{
176176
user: 'user:anne',
177177
relation: 'reader',
178-
object: 'document:Z',
178+
object: 'document:Z'
179179
}
180180
```
181181

@@ -184,7 +184,7 @@ Assume that you want to delete user `user:anne`'s `reader` relationship with obj
184184
{
185185
user: 'user:anne',
186186
relation: 'reader',
187-
object: 'document:Z',
187+
object: 'document:Z'
188188
},
189189
]}
190190
skipSetup={true}
@@ -199,11 +199,113 @@ Assume that you want to delete user `user:anne`'s `reader` relationship with obj
199199
]}
200200
/>
201201

202+
### 04. Writing and deleting relationship tuples in the same request
203+
204+
You can combine both writes and deletes in a single transactional API request. This is useful when you need to update multiple relationships atomically. All operations in the request will either succeed together or fail together.
205+
206+
The Write API allows you to send up to `100` unique tuples in the request. (This limit applies to the sum of both writes and deletes in that request).
207+
208+
For example, you might want to remove `user:anne` as a `writer` of `document:Z` while simultaneously updating `user:anne` as an `reader` of `document:Z`:
209+
210+
<WriteRequestViewer
211+
relationshipTuples={[
212+
{
213+
user: 'user:anne',
214+
relation: 'reader',
215+
object: 'document:Z'
216+
},
217+
]}
218+
deleteRelationshipTuples={[
219+
{
220+
user: 'user:anne',
221+
relation: 'writer',
222+
object: 'document:Z'
223+
},
224+
]}
225+
skipSetup={true}
226+
allowedLanguages={[
227+
SupportedLanguage.JS_SDK,
228+
SupportedLanguage.GO_SDK,
229+
SupportedLanguage.DOTNET_SDK,
230+
SupportedLanguage.PYTHON_SDK,
231+
SupportedLanguage.JAVA_SDK,
232+
SupportedLanguage.CLI,
233+
SupportedLanguage.CURL,
234+
]}
235+
/>
236+
237+
This approach ensures that both operations succeed or fail together, maintaining transactional data consistency.
238+
239+
240+
:::note
241+
When using the Write API, you cannot include the same tuple (same user, relation, and object) in the writes or deletes arrays within a single request. The API will return an error with code `cannot_allow_duplicate_tuples_in_one_request` if detected.
242+
:::
243+
244+
### 05. Ignoring duplicate or missing tuples
245+
246+
Sometimes you might need to write a tuple that already exists, which would normally cause the whole request to fail. You can use the `on_duplicate: "ignore"` parameter to handle this gracefully.
247+
248+
This is particularly useful for high-volume data imports, migrations, or ensuring certain permissions exist without complex error handling logic.
249+
250+
For example, if you want to ensure `user:anne` has `reader` access to `document:Z` without worrying about whether the relationship already exists in <ProductName format={ProductNameFormat.ShortForm}/>:
251+
252+
<WriteRequestViewer
253+
relationshipTuples={[
254+
{
255+
user: 'user:anne',
256+
relation: 'reader',
257+
object: 'document:Z'
258+
},
259+
]}
260+
writeOptions={{
261+
on_duplicate: 'ignore',
262+
}}
263+
skipSetup={true}
264+
allowedLanguages={[
265+
SupportedLanguage.CURL,
266+
]}
267+
/>
268+
269+
:::caution
270+
At the moment, this feature is only available on the API (v1.10.0). Supported SDKs will follow shortly after.
271+
:::
272+
273+
Similarly, you can use `on_missing: "ignore"` when deleting tuples that might not exist.
274+
275+
<WriteRequestViewer
276+
skipSetup={true}
277+
deleteRelationshipTuples={[
278+
{
279+
user: 'user:anne',
280+
relation: 'writer',
281+
object: 'document:Z'
282+
},
283+
]}
284+
deleteOptions={{
285+
on_missing: 'ignore',
286+
}}
287+
expectedResponse={{
288+
data: {},
289+
}}
290+
allowedLanguages={[
291+
SupportedLanguage.CURL,
292+
]}
293+
/>
294+
295+
The behavior of `on_duplicate: "ignore"` is more nuanced for tuples with conditions.
296+
- **Identical Tuples**: If a tuple in the request is identical to an existing tuple (same user, relation, object, condition name, and condition context), it will be safely ignored.
297+
- **Conflicting Tuples**: If a tuple key (user, relation, object) matches an existing tuple, but the condition name or parameters are different, this is a conflict. The write attempt will be rejected, and the entire transaction will fail with a `409 Conflict` error.
298+
202299
## Related Sections
203300

204301
<RelatedSection
205302
description="Check the following sections for more on how to write your authorization data"
206303
relatedLinks={[
304+
{
305+
title: 'Write API',
306+
description: 'Learn more about the Write API options.',
307+
link: '/api/service#Relationship%20Tuples/Write',
308+
},
207309
{
208310
title: 'Managing User Access',
209311
description: 'Learn about how to give a user access to a particular object.',
@@ -216,11 +318,5 @@ Assume that you want to delete user `user:anne`'s `reader` relationship with obj
216318
link: '../interacting/managing-group-access',
217319
id: '../interacting/managing-group-access.mdx',
218320
},
219-
{
220-
title: 'Transactional Writes',
221-
description: 'Learn about how to update multiple relations within the same API call.',
222-
link: '../interacting/transactional-writes',
223-
id: '../interacting/transactional-writes.mdx',
224-
},
225321
]}
226322
/>

docs/content/interacting/overview.mdx

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -42,11 +42,6 @@ This section helps you integrate <ProductName format={ProductNameFormat.ShortFor
4242
'Write relationship tuples to manage how two objects are related. E.g. parent folder and child document.',
4343
to: 'interacting/managing-relationships-between-objects',
4444
},
45-
{
46-
title: 'Transactional Writes',
47-
description: 'Write multiple relationship tuples in a single request, so all writes either succeed or fail.',
48-
to: 'interacting/transactional-writes',
49-
},
5045
{
5146
title: 'Relationship Queries',
5247
description: 'An overview of how to use the Check, Read, Expand, and ListObject APIs.',

0 commit comments

Comments
 (0)