# Records Interface
## Context
Prior to the refactor in May 2023, the the DWN Records API was:
```typescript
const { record } = await web5.dwn.records.create(targetDid, {
author: authorDid,
data: ...,
message: { ... }
});
```
This meant that even when a Web5 app's primary user was writing to their own DWN they had to specify their own DID as the target for every request:
```typescript
const { record } = await web5.dwn.records.create('did:example:alice', {
author: 'did:example:alice',
data: 'Hello World!',
message: {
dataFormat: 'text/plain'
}
});
```
The original issue that prompted the refactor:
- How does a developer specify whether that message should be written to Alice's local DWN (in-browser/in-memory DWN instance) or to Alice's remote DWN (e.g., https://dwn.tbddev.org/dwn0)?
There was no way to specify this in the external API, and consequently, logic had been added behind the scenes to attempt to discover where there was a local DWN and whether author keys existed to write to it. Messages would flow through conditional routing depending on these checks, which were difficult to troubleshoot and reason about.
Additionally, a variety of other scenarios weren't account for, such as the case where a single message needed to be written to two different entities (Alice sends to Bob and Carol).
## Changes Implemented
The refactor had the following effects:
### `web5.dwn.records.*` usage:
**`author` and `target` no longer have to be specified in _every_ message**
- The author that signs the record will always be the currently active/connected DID of the `Web5UserAgent` instance such that the `author:` property doesn't need to be specified in every `web5.dwn.*.*` invocation.
- Unless otherwise specified, record operations default to targeting the tenant of the currently active DID of the `Web5UserAgent` instance such that the `target:` property doesn't need to be specified in every `web5.dwn.*.*` invocation.
**`from` added to `web5.dwn.*.*`**
- For `delete()`, `query()`, and `read()` operations, specifying `from: bobDid` will indicate that this record operation should be executed by the DWN endpoint in `bobDid`'s DID document.
- The property was named `from` to mirror the well-known SQL syntax: `The FROM command is used to specify which table to select or delete data from`. Therefore, a `delete()` operation with `from: bobDid` would delete the record _from_ Bob's DWN and a `read()` operation with `from: carolDid` would read the record _from_ Carol's DWN.
**`store: false` added to `web5.dwn.records.create()`**
- When creating/writing a record, `store: false` indicates that the message should NOT be persisted to the in-page/browser DWN. This is typically only used in the case where the developer intent is that the record will either NEVER be written to the active DID's datastores OR in the case where writing to the active DID's in-page/browser or `dwn-server` endpoint DWNs should ONLY happen after the initial writes to some other entity are successful. A scenario might be: "only write this record to my DWN if the record can be successfully written to service provider's DWN."
**`send()` instance method added to the `Record` model class**
- Calling `record.send(did)` after the initial write will have the effect of transporting the message/data to the service endpoint in the DID document of the specified `did`.
- A single record can be sent to multiple DWNs by repeatedly calling `record.send(did)` with a status returned for each attempt to transport the record over a network. For example, Alice might write a record to Bob's remote DWN first, then Carol's remote DWN, and finally Alice's own remote DWN.
- By taking this appraoch, a developer gets a single status response for each request and can decide whether to retry or cancel in the effort the initial request returns an error. In the case of multiple calls to `send()` a developer can decide whether these should be done in sequence, parallel, etc.
### Simplified Explanation
By taking the above approach, the intent was to provide a consistent mental model for developers when using `web5.dwn.*.*` methods.
- Unless otherwise specified, `web5.dwn.recods.*` and `web5.dwn.protocols.*` requests are always excecuted on the local/in-memory DWN.
- If a record or protocol operation needs to be executed on another entity's DWN, `record.send(did)` and `protocol.send(did)` can be used.
## All Permutations for `create()` / `write()`
In considering which approach to select, we were careful to ensure that all permutations of local and remote requests were accounted for:
#### 1. Only Alice's local:
```typescript
const { record, status } = await web5.dwn.records.create({
message: {
"schema": 'whatever'
},
data: 'hi'
});
```
#### 2. Only Alice's remote:
```typescript
const { record, status } = await web5.dwn.records.create({
store: false,
message: {
"schema": 'whatever'
},
data: 'hi'
});
await record.send(aliceDid);
```
#### 3. Only Bob's remote:
```typescript
const { record, status } = await web5.dwn.records.create({
store: false,
message: {
"schema": 'whatever'
},
data: 'hi'
});
await record.send(bobDid);
```
#### 4. Alice's local + Alice's remote:
```typescript
const { record, status } = await web5.dwn.records.create({
data: 'hi',
message: {
"schema": 'whatever'
}
});
await record.send(aliceDid);
```
#### 5. Alice's local + Bob's remote:
```typescript
const { record, status } = await web5.dwn.records.create({
message: {
"schema": 'whatever'
},
data: 'hi'
});
await record.send(bobDid);
```
#### 6. Alice's remote + Alice's local:
:::danger
IMPOSSIBLE
:::
```typescript
const { record } = await web5.dwn.records.create({
store: false
data: 'hi',
message: {
"schema": 'whatever'
}
});
await record.send(alice);
// No way to write to Alice's local at this point.
```
#### 7. Alice's remote + Bob's remote:
```typescript
const { record, status } = await web5.dwn.records.create({
store: false,
message: {
"schema": 'whatever'
},
data: 'hi'
});
await record.send(aliceDid);
await record.send(bobDid);
```
#### 8. Bob's remote + Alice's local:
:::danger
IMPOSSIBLE
:::
```typescript
const { record, status } = await web5.dwn.records.create({
store: false,
message: {
"schema": 'whatever'
},
data: 'hi'
});
await record.send(bobDid);
// No way to write to Alice's local at this point.
```
#### 9. Bob's remote + Alice's remote:
```typescript
const { record } = await web5.dwn.records.create({
store: false,
data: 'hi',
message: {
"schema": 'whatever'
}
});
await record.send(bobDid);
await record.send(aliceDid);
```
#### 10. Alice's local + Alice's remote + Bob's remote:
```typescript
const { record } = await web5.dwn.records.create({
data: 'hi',
message: {
"schema": 'whatever'
}
});
await record.send(aliceDid);
await record.send(bobDid);
```
#### 11. Alice's local + Bobs's remote + Alice's remote:
```typescript
const { record } = await web5.dwn.records.create({
data: 'hi',
message: {
"schema": 'whatever'
}
});
await record.send(bobDid);
await record.store(aliceDid);
```
#### 12. Alice's remote + Alice's local + Bob's remote:
:::danger
IMPOSSIBLE
:::
```typescript
const { record } = await web5.dwn.records.create({
store: false,
data: 'hi',
message: {
"schema": 'whatever'
}
});
// No way to write to Alice's local at this point.
await record.send(bobDid);
```
#### 13. Alice's remote + Bob's remote + Alice's local:
:::danger
IMPOSSIBLE
:::
```typescript
const { record } = await web5.dwn.records.write({
store: false,
data: 'hi',
message: {
"schema": 'whatever'
}
});
await record.send(bobDid);
// No way to write to Alice's local at this point.
```
#### 14. Bob's remote + Alice's local + Alice's remote:
:::danger
IMPOSSIBLE
:::
```typescript
const { record } = await web5.dwn.records.write({
store: false,
data: 'hi',
message: {
"schema": 'whatever'
}
});
// No way to write to Alice's local at this point.
await record.send(aliceDid);
```
#### 15. Bob's remote + Alice's remote + Alice's local:
:::danger
IMPOSSIBLE
:::
```typescript
const { record } = await web5.dwn.records.write({
store: false,
data: 'hi',
message: {
"schema": 'whatever'
}
});
await record.send(bobDid);
// No way to write to Alice's local at this point.
```
## All other `web5.dwn.*.*`
### `query()`
1. Alice's local
```typescript
web5.dwn.records.query({
message: {
filter: {
contextId: thread.contextId
}
}
});
```
2. Alice's remote
```typescript
web5.dwn.records.query({
from: aliceDid,
message: {
filter: {
contextId: thread.contextId
}
}
});
```
3. Bob's remote
```typescript
web5.dwn.records.query({
from: bobDid,
message: {
filter: {
contextId: thread.contextId
}
}
});
```
### `read()`
1. Alice's local
```typescript
web5.dwn.records.read({
message: {
recordId: thread.recordId
}
});
```
2. Alice's remote
```typescript
web5.dwn.records.query({
from: aliceDid,
message: {
recordId: thread.recordId
}
});
```
3. Bob's remote
```typescript
web5.dwn.records.query({
from: bobDid,
message: {
recordId: thread.recordId
}
});
```
### `delete()`
1. Alice's local
```typescript
web5.dwn.records.read({
message: {
recordId: thread.recordId
}
});
```
2. Alice's remote
```typescript
web5.dwn.records.read({
from: aliceDid,
message: {
recordId: thread.recordId
}
});
```
3. Bob's remote
```typescript
web5.dwn.records.read({
from: bobDid,
message: {
recordId: thread.recordId
}
});
```
## All Permutations with failure scenarios
#### 1. Only Alice's local:
```typescript
const { record, status } = await web5.dwn.records.create({
message: {
schema: 'whatever'
},
data: 'hi'
});
```
**Failure Scenarios**
**`Write to your local/agent fails`**
```typescript
// Retry by attempting to write the record again.
const { record, status } = await web5.dwn.records.create({
message: {
schema: 'whatever'
},
data: 'hi'
});
```
---
#### 2. Only Alice's remote:
```typescript
const { record, status } = await web5.dwn.records.create({
store: false,
message: {
"schema": 'whatever'
},
data: 'hi'
});
await record.send(aliceDid);
```
**Failure Scenarios**
**`Write to your remote/endpoint(s) all fail`**
```typescript
// Retry sending to Alice's remote DWN.
await record.send(aliceDid);
```
---
#### 3. Only Bob's remote:
```typescript
const { record, status } = await web5.dwn.records.create({
store: false,
message: {
"schema": 'whatever'
},
data: 'hi'
});
await record.send(bobDid);
```
**Failure Scenarios**
**`Write to Bob endpoint(s) all fail`**
```typescript
// Retry sending to Bob's remote DWN.
await record.send(bobDid);
```
---
#### 4. Alice's local + Alice's remote:
```typescript
const { record, status } = await web5.dwn.records.create({
data: 'hi',
message: {
"schema": 'whatever'
}
});
await record.send(aliceDid);
```
**Failure Scenarios**
**i. `Write to local/agent fails`**
```typescript
// Retry by attempting to write the record again.
const { record, status } = await web5.dwn.records.create({
message: {
schema: 'whatever'
},
data: 'hi'
});
// If write to local/agents succeeds this time, then retry remote/endpoint(s)
await record.send(aliceDid);
```
**ii. `Write to local/agent succeeds but remote/endpoint(s) all fail`**
```typescript
// retry just remote/endpoint(s)
await record.send(aliceDid);
```
---
#### 5. Alice's local + Bob's remote:
```typescript
const { record, status } = await web5.dwn.records.create({
message: {
"schema": 'whatever'
},
data: 'hi'
});
await record.send(bobDid);
```
**Failure Scenarios**
**i. `Write to local/agent fails`**
```typescript
// Retry by attempting to write the record again.
const { record, status } = await web5.dwn.records.create({
message: {
schema: 'whatever'
},
data: 'hi'
});
// if write to local/agents succeeds this time, then retry Bob's endpoint(s)
await record.send(bobDid);
```
**ii. `Write to local/agent succeeds but Bob endpoint(s) all fail`**
```typescript
// retry just Bob's endpoint(s)
await record.send(bobDid);
```
---
#### 6. Alice's remote + Alice's local:
:::danger
IMPOSSIBLE
:::
```typescript
const { record } = await web5.dwn.records.create({
store: false
data: 'hi',
message: {
"schema": 'whatever'
}
});
await record.send(alice);
// No way to write to Alice's local at this point.
```
**Failure Scenarios**
**i. `Write to your remote/endpoint(s) all fail`**
```typescript
// retry remote/endpoint(s)
record.store('endpoints');
// if write to remote/endpoint(s) succeed this time, then retry local/agent
record.store('agent');
```
**ii. `Write to your remote/endpoint(s) succeeds but local/agent fail`**
```typescript
// retry just local/agent
record.store('agent');
```
---
#### 7. Your own remote + someone else's remote:
```typescript=
const { record, status } = await web5.dwn.records.write({
store: 'endpoints',
to: bobDid,
message: {
"schema": 'whatever'
},
data: 'hi'
});
await record.send(bobDid);
```
**Failure Scenarios**
**i. `Write to your remote/endpoint(s) all fail`**
```typescript
// retry remote/endpoint(s)
record.store('endpoints');
// if write to remote/endpoint(s) succeed this time, then retry Bob's endpoint(s)
await record.send(bobDid);
```
**ii. `Write to your remote/endpoint(s) succeeds but Bob endpoint(s) all fail`**
```typescript
// retry just Bob's endpoint(s)
await record.send(bobDid);
```
---
8. Someone else's remote + your own local:
```typescript=
const { record, status } = await web5.dwn.records.write({
store: false,
to: bobDid,
message: {
"schema": 'whatever'
},
data: 'hi'
});
await record.send(bobDid);
await record.store('agent');
```
**Failure Scenarios**
**i. `Write to Bob's endpoint(s) all fail`**
```typescript
// retry Bob's endpoint(s)
await record.send(bobDid);
// if write to Bob's endpoint(s) succeeds this time, then retry local/agent
await record.store('agent');
```
**ii. `Write to Bob's endpoint(s) succeeds but local/agent fails`**
```typescript
// retry just Bob's endpoint(s)
await record.store('agent');
```
---
9. Someone else's remote + your own remote:
```typescript=
const { record } = await web5.dwn.records.write({
to: bobDid,
store: false,
data: 'hi',
message: {
"schema": 'whatever'
}
});
await record.send(bobDid);
await record.store('endpoints');
```
**Failure Scenarios**
**i. `Write to Bob's endpoint(s) all fail`**
```typescript
// retry Bob's endpoint(s)
await record.send(bobDid);
// if write to Bob's endpoint(s) succeeds this time, then retry remote/endpoint(s)
await record.store('endpoints');
```
**ii. `Write to Bob's endpoint(s) succeeds but remote/endpoint(s) all fail`**
```typescript
// retry remote/endpoint(s)
await record.store('endpoints');
```
---
10. Your own local + your own remote + someone else's remote:
```typescript=
const { record } = await web5.dwn.records.write({
to: bobDid,
store: 'agent',
data: 'hi',
message: {
"schema": 'whatever'
}
});
await record.store('endpoints');
await record.send(bobDid);
```
**Failure Scenarios**
**i. `Write to local/agent fails`**
```typescript
// retry local/agent first
await record.store('agent');
// if write to local/agent succeeds this time, then retry your remote/endpoint(s)
await record.store('endpoints');
// if write to local/agent and remote/endpoint(s) succeed this time, retry Bob's endpoint(s)
await record.send(bobDid);
```
**ii. `Write to local/agent succeeds but your remote/endpoint(s) all fail`**
```typescript
// retry your remote/endpoint(s)
await record.store('endpoints');
// if write to your remote/endpoint(s) succeed this time, retry Bob's endpoint(s)
await record.send(bobDid);
```
**iii. `Write to local/agent and remote/endpoint(s) succeed but Bob's endpoint(s) all fail`**
```typescript
// retry Bob's endpoint(s)
await record.send(bobDid);
```
---
11. Your own local + someone else's remote + your own remote:
```typescript=
const { record } = await web5.dwn.records.write({
to: bobDid,
store: 'agent',
data: 'hi',
message: {
"schema": 'whatever'
}
});
await record.send(bobDid);
await record.store('endpoints');
```
**Failure Scenarios**
**i. `Write to local/agent fails`**
```typescript
// retry local/agent first
await record.store('agent');
// if write to local/agent succeeds this time, then retry Bob's endpoint(s)
await record.send(bobDid);
// if write to local/agent and Bob's endpoint(s) succeed this time, retry your remote/endpoint(s)
await record.store('endpoints');
```
**ii. `Write to local/agent succeeds but Bob's endpoint(s) all fail`**
```typescript
// retry Bob's endpoint(s)
await record.send(bobDid);
// if write to Bob's endpoint(s) succeed this time, retry your remote/endpoint(s)
await record.store('endpoints');
```
**iii. `Write to local/agent and Bob's endpoint(s) succeed but your remote/endpoint(s) all fail`**
```typescript
// retry your remote/endpoint(s)
await record.store('endpoints');
```
---
12. Your own remote + your own local + someone else's remote:
```typescript=
const { record } = await web5.dwn.records.write({
to: bobDid,
store: 'endpoints',
data: 'hi',
message: {
"schema": 'whatever'
}
});
await record.store('agent');
await record.send(bobDid);
```
**Failure Scenarios**
**i. `Write to your remote/endpoint(s) all fail`**
```typescript
// retry remote/endpoint(s) first
await record.store('endpoints');
// if write to remote/endpoint(s) succeed this time, then retry your local/agent
await record.store('agent');
// if write to remote/endpoint(s) and your local/agent succeed this time, retry Bob's endpoint(s)
await record.send(bobDid);
```
**ii. `Write to remote/endpoint(s) succeeds but your local/agent fails`**
```typescript
// retry your local/agent
await record.store('agent');
// if write to your local/agent succeed this time, retry Bob's endpoint(s)
await record.send(bobDid);
```
**iii. `Write to remote/endpoint(s) and local/agent succeeds, but Bob's endpoint(s) all fail`**
```typescript
// retry Bob's endpoint(s)
await record.send(bobDid);
```
---
13. Your own remote + someone else's remote + your own local:
```typescript=
const { record } = await web5.dwn.records.write({
to: bobDid,
store: 'endpoints',
data: 'hi',
message: {
"schema": 'whatever'
}
});
await record.send(bobDid);
await record.store('agent');
```
**Failure Scenarios**
**i. `Write to your remote/endpoint(s) all fail`**
```typescript
// retry remote/endpoint(s) first
await record.store('endpoints');
// if write to remote/endpoint(s) succeed this time, then retry Bob's endpoint(s)
await record.send(bobDid);
// if write to remote/endpoint(s) and Bob's endpoint(s) succeed this time, retry your local/agent
await record.store('agent');
```
**ii. `Write to your remote/endpoint(s) succeeds but Bob's endpoint(s) all fail`**
```typescript
// retry Bob's endpoint(s)
await record.send(bobDid);
// if write to Bob's endpoint(s) succeed this time, retry your local/agent
await record.store('agent');
```
**iii. `Write to remote/endpoint(s) and Bob's endpoint(s) succeed, but local/agent fails`**
```typescript
// retry your local/agent
await record.store('agent');
```
---
14. Someone else's remote + your own local + your own remote:
```typescript=
const { record } = await web5.dwn.records.write({
to: bobDid,
store: false,
data: 'hi',
message: {
"schema": 'whatever'
}
});
await record.store('agent');
await record.store('endpoints');
```
**Failure Scenarios**
**i. `Write to Bob's endpoint(s) all fail`**
```typescript
// retry Bob's endpoint(s) first
await record.send(bobDid);
// if write to Bob's endpoint(s) succeed this time, then retry your local/agent
await record.store('agent');
// if write to Bob's endpoints and your local/agent succeed this time, retry your remote/endpoint(s)
await record.store('endpoints');
```
**ii. `Write to Bob's endpoint(s) succeeds but your local/agent fails`**
```typescript
// retry your local/agent
await record.store('agent');
// if write to your your local/agent succeeds this time, retry your remote/endpoint(s)
await record.store('endpoints');
```
**iii. `Write to Bob's endpoint(s) and your local/agent succeed, but remote/endpoint(s) fail`**
```typescript
// retry your remote/endpoint(s)
await record.store('endpoints');
```
---
15. Someone else's remote + your own remote + your own local:
```typescript=
const { record } = await web5.dwn.records.write({
to: bobDid,
store: false,
data: 'hi',
message: {
"schema": 'whatever'
}
});
await record.store('endpoints');
await record.store('agent');
```
**Failure Scenarios**
**i. `Write to Bob's endpoint(s) all fail`**
```typescript
// retry Bob's endpoint(s) first
await record.send(bobDid);
// if write to Bob's endpoint(s) succeed this time, then retry your remote/endpoint(s)
await record.store('endpoints');
// if write to Bob's endpoints and your remote/endpoint(s) succeed this time, retry your local/agent
await record.store('agent');
```
**ii. `Write to Bob's endpoint(s) succeeds but your remote/agent fails`**
```typescript
// retry your remote/endpoint(s)
await record.store('endpoints');
// if write to your remote/endpoint(s) succeed this time, retry your local/agent
await record.store('agent');
```
**iii. `Write to Bob's endpoint(s) and your remote/endpoint(s) succeed, but local/agent fails`**
```typescript
// retry your local/agent
await record.store('agent');
```