Writing Data

Write AT Protocol Records

Writing Data

Writing data — for example, by posting to a Bluesky feed — works similarly to reading data, but with different methods.

To create a new record, call client.create() with an imported Lexicon, along with any required fields:

import * as app from './lexicons/app.js'

const result = await client.create(app.bsky.feed.post, {
  text: 'Hello, world!',
  createdAt: new Date().toISOString(),
})

text and createdAt are required values under the app.bsky.feed.post Lexicon.

The API will respond with the at:// URI of the post and a content hash of the post as the cid:

console.log(result.uri) // at://did:plc:...
console.log(result.cid)
{
  "uri": "at://did:plc:u5cwb2mwiv2bfq53cjufe6yn/app.bsky.feed.post/3k4duaz5vfs2b",
  "cid": "bafyreibjifzpqj6o6wcq3hejh7y4z4z2vmiklkvykc57tw3pcbx3kxifpm"
}

If you are building a client or another interface that both reads and writes data, it is important to ensure that you read your own writes using this response.

Read-after-Write

Depending on how an AT app frontend is designed, a user may take some action (such as updating their profile), rapidly refresh the view, and find that their recent change is not immediately reflected in the updated response.

This is because services such as the App View do not have transactional writes from a user's PDS. Therefore the views that they calculate are eventually consistent. In other words, a user may have created a record on their PDS that is not yet reflected in the API responses provided by the App View.

Because all requests from the application are sent to the user's PDS, the PDS is in a position to smooth over this behavior. Our PDS distribution provides some basic read-after-write behaviors by looking at response headers from the App View, determining if there are any new records that are not in the response, and modifying the response to reflect those new records.

The App View communicates the current state of its indices by setting the Atproto-Repo-Rev response header. This is set by the rev of the most recent commit that's been indexed from the requesting user's repository. If the PDS sees this header on a response, it will search for all records that it has locally that are more recent than the provided rev and determine if they affect the App View's response.

This read-after-write behavior only applies to records from the user making the request. Records from other users that happen to be on the same PDS will not affect the requesting user's response.

Updating Records

To update an existing record, like a user's profile, use client.put():

lex install app.bsky.actor.profile
lex build
import * as app from './lexicons/app.js'

await client.put(app.bsky.actor.profile, {
  displayName: 'New Name',
  description: 'Updated bio',
})

Deleting Records

To delete a record, like an individual post, use client.delete():

lex install app.bsky.actor.post
lex build
import * as app from './lexicons/app.js'

await client.delete(app.bsky.feed.post, {
  rkey: '3jxf7z2k3q2',
})

Further Reading and Resources