
Security News
curl Shuts Down Bug Bounty Program After Flood of AI Slop Reports
A surge of AI-generated vulnerability reports has pushed open source maintainers to rethink bug bounties and tighten security disclosure processes.
@sanity/client
Advanced tools
Javascript client for Sanity. Works in node.js and modern browsers (older browsers needs a Promise polyfill).
Sanity Client requires the JavaScript runtime to have a global ES6-compliant Promise available. If your runtime environment doesn't provide a spec compliant Promise implementation, we recommend using native-promise-only, es6-promise or another spec-compliant implementation. See this article for more information.
The client can be installed from npm:
npm install -g @sanity/client
const sanityClient = require('@sanity/client')
const client = sanityClient({
projectId: 'your-project-id',
dataset: 'bikeshop',
apiVersion: '2021-03-25', // use current UTC date - see "specifying API version"!
token: 'sanity-auth-token', // or leave blank for unauthenticated usage
useCdn: true, // `false` if you want to ensure fresh data
})
const client = sanityClient(options)
Initializes a new Sanity Client. Required options are projectId, dataset, and apiVersion. Setting a value for useCdn is encouraged.
Sanity uses ISO dates (YYYY-MM-DD) in UTC timezone for versioning. The explanation for this can be found in the documentation
In general, unless you know what API version you want to use, you'll want to set it to today's UTC date. By doing this, you'll get all the latest bugfixes and features, while locking the API to prevent breaking changes.
Note: Do not be tempted to use a dynamic value for the apiVersion. The reason for setting a static value is to prevent unexpected, breaking changes.
In future versions, specifying an API version will be required. For now (to maintain backwards compatiblity) not specifying a version will trigger a deprecation warning and fall back to using v1.
const query = '*[_type == "bike" && seats >= $minSeats] {name, seats}'
const params = {minSeats: 2}
client.fetch(query, params).then((bikes) => {
console.log('Bikes with more than one seat:')
bikes.forEach((bike) => {
console.log(`${bike.name} (${bike.seats} seats)`)
})
})
client.fetch(query, params = {})
Perform a query using the given parameters (if any).
const query = '*[_type == "comment" && authorId != $ownerId]'
const params = {ownerId: 'bikeOwnerUserId'}
const subscription = client.listen(query, params).subscribe((update) => {
const comment = update.result
console.log(`${comment.author} commented: ${comment.text}`)
})
// to unsubscribe later on
subscription.unsubscribe()
client.listen(query, params = {}, options = {includeResult: true})
Open a query that listens for updates on matched documents, using the given parameters (if any). The return value is an RxJS Observable. When calling .subscribe() on the returned observable, a subscription is returned, and this can be used to unsubscribe from the query later on by calling subscription.unsubscribe()
The update events which are emitted always contain mutation, which is an object containing the mutation which triggered the document to appear as part of the query.
By default, the emitted update event will also contain a result property, which contains the document with the mutation applied to it. In case of a delete mutation, this property will not be present, however. You can also tell the client not to return the document (to save bandwidth, or in cases where the mutation or the document ID is the only relevant factor) by setting the includeResult property to false in the options.
Likewise, you can also have the client return the document before the mutation was applied, by setting includePreviousRevision to true in the options, which will include a previous property in each emitted object.
This will fetch a document from the Doc endpoint. This endpoint cuts through any caching/indexing middleware that may involve delayed processing. As it is less scalable/performant than the other query mechanisms, it should be used sparingly. Performing a query is usually a better option.
client.getDocument('bike-123').then((bike) => {
console.log(`${bike.name} (${bike.seats} seats)`)
})
This will fetch multiple documents in one request from the Doc endpoint. This endpoint cuts through any caching/indexing middleware that may involve delayed processing. As it is less scalable/performant than the other query mechanisms, it should be used sparingly. Performing a query is usually a better option.
client.getDocuments(['bike123', 'bike345']).then(([bike123, bike345]) => {
console.log(`Bike 123: ${bike123.name} (${bike123.seats} seats)`)
console.log(`Bike 345: ${bike345.name} (${bike345.seats} seats)`)
})
Note: Unlike in the HTTP API, the order/position of documents is preserved based on the original array of IDs. If any of the documents are missing, they will be replaced by a null entry in the returned array:
const ids = ['bike123', 'nonexistent-document', 'bike345']
client.getDocuments(ids).then((docs) => {
// the docs array will be:
// [{_id: 'bike123', ...}, null, {_id: 'bike345', ...}]
})
const doc = {
_type: 'bike',
name: 'Sanity Tandem Extraordinaire',
seats: 2,
}
client.create(doc).then((res) => {
console.log(`Bike was created, document ID is ${res._id}`)
})
client.create(doc)
Create a document. Argument is a plain JS object representing the document. It must contain a _type attribute. It may contain an _id. If an ID is not specified, it will automatically be created.
To create a draft document, add an _id attribute set to 'drafts.'.
const doc = {
_id: 'my-bike',
_type: 'bike',
name: 'Sanity Tandem Extraordinaire',
seats: 2,
}
client.createOrReplace(doc).then((res) => {
console.log(`Bike was created, document ID is ${res._id}`)
})
client.createOrReplace(doc)
If you are not sure whether or not a document exists but want to overwrite it if it does, you can use the createOrReplace() method. When using this method, the document must contain an _id attribute.
const doc = {
_id: 'my-bike',
_type: 'bike',
name: 'Sanity Tandem Extraordinaire',
seats: 2,
}
client.createIfNotExists(doc).then((res) => {
console.log('Bike was created (or was already present)')
})
client.createIfNotExists(doc)
If you want to create a document if it does not already exist, but fall back without error if it does, you can use the createIfNotExists() method. When using this method, the document must contain an _id attribute.
client
.patch('bike-123') // Document ID to patch
.set({inStock: false}) // Shallow merge
.inc({numSold: 1}) // Increment field by count
.commit() // Perform the patch and return a promise
.then((updatedBike) => {
console.log('Hurray, the bike is updated! New document:')
console.log(updatedBike)
})
.catch((err) => {
console.error('Oh no, the update failed: ', err.message)
})
Modify a document. patch takes a document ID. set merges the partialDoc with the stored document. inc increments the given field with the given numeric value. commit executes the given patch. Returns the updated object.
client.patch('bike-123').setIfMissing({title: 'Untitled bike'}).commit()
client.patch('bike-123').unset(['title', 'price']).commit()
client
.patch('bike-123')
.inc({price: 88, numSales: 1}) // Increment `price` by 88, `numSales` by 1
.dec({inStock: 1}) // Decrement `inStock` by 1
.commit()
You can use the ifRevisionId(rev) method to specify that you only want the patch to be applied if the stored document matches a given revision.
client
.patch('bike-123')
.ifRevisionId('previously-known-revision')
.set({title: 'Little Red Tricycle'})
.commit()
The patch operation insert takes a location (before, after or replace), a path selector and an array of elements to insert.
const {nanoid} = require('nanoid')
client
.patch('bike-123')
// Ensure that the `reviews` arrays exists before attempting to add items to it
.setIfMissing({reviews: []})
// Add the items after the last item in the array (append)
.insert('after', 'reviews[-1]', [
// Add a `_key` unique within the array to ensure it can be addressed uniquely
// in a real-time collaboration context
{_key: nanoid(), title: 'Great bike!', stars: 5},
])
.commit()
The operations of appending and prepending to an array are so common that they have been given their own methods for better readability:
const {nanoid} = require('nanoid')
client
.patch('bike-123')
.setIfMissing({reviews: []})
.append('reviews', [{_key: nanoid(), title: 'Great bike!', stars: 5}])
.commit()
Each entry in the unset array can be either an attribute or a JSON path.
In this example, we remove the first review and the review with _key: 'abc123' from the bike.reviews array:
const reviewsToRemove = ['reviews[0]', 'reviews[_key=="abc123"]']
client.patch('bike-123').unset(reviewsToRemove).commit()
client
.delete('bike-123')
.then((res) => {
console.log('Bike deleted')
})
.catch((err) => {
console.error('Delete failed: ', err.message)
})
client.delete(docId)
Delete a document. Parameter is a document ID.
const namePatch = client.patch('bike-310').set({name: 'A Bike To Go'})
client
.transaction()
.create({name: 'Sanity Tandem Extraordinaire', seats: 2})
.delete('bike-123')
.patch(namePatch)
.commit()
.then((res) => {
console.log('Whole lot of stuff just happened')
})
.catch((err) => {
console.error('Transaction failed: ', err.message)
})
client.transaction().create(doc).delete(docId).patch(patch).commit()
Create a transaction to perform chained mutations.
client
.transaction()
.create({name: 'Sanity Tandem Extraordinaire', seats: 2})
.patch('bike-123', (p) => p.set({inStock: false}))
.commit()
.then((res) => {
console.log('Bike created and a different bike is updated')
})
.catch((err) => {
console.error('Transaction failed: ', err.message)
})
client.transaction().create(doc).patch(docId, p => p.set(partialDoc)).commit()
A patch can be performed inline on a transaction.
Transactions and patches can also be built outside the scope of a client:
const sanityClient = require('@sanity/client')
const client = sanityClient({
projectId: 'your-project-id',
dataset: 'bikeshop',
})
// Patches:
const patch = new sanityClient.Patch('<documentId>')
client.mutate(patch.inc({count: 1}).unset(['visits']))
// Transactions:
const transaction = new sanityClient.Transaction()
.create({_id: '123', name: 'FooBike'})
.delete('someDocId')
client.mutate(transaction)
const patch = new sanityClient.Patch(docId)
const transaction = new sanityClient.Transaction()
An important note on this approach is that you cannot call commit() on transactions or patches instantiated this way, instead you have to pass them to client.mutate()
Assets can be uploaded using the client.assets.upload(...) method.
client.assets.upload(type: 'file' | image', body: File | Blob | Buffer | NodeStream, options = {}): Promise<AssetDocument>
👉 Read more about assets in Sanity
// Upload a file from the file system
client.assets
.upload('file', fs.createReadStream('myFile.txt'), {filename: 'myFile.txt'})
.then((document) => {
console.log('The file was uploaded!', document)
})
.catch((error) => {
console.error('Upload failed:', error.message)
})
// Upload an image file from the file system
client.assets
.upload('image', fs.createReadStream('myImage.jpg'), {filename: 'myImage.jpg'})
.then((document) => {
console.log('The image was uploaded!', document)
})
.catch((error) => {
console.error('Upload failed:', error.message)
})
// Create a file with "foo" as its content
const file = new File(['foo'], 'foo.txt', {type: 'text/plain'})
// Upload it
client.assets
.upload('file', file)
.then((document) => {
console.log('The file was uploaded!', document)
})
.catch((error) => {
console.error('Upload failed:', error.message)
})
// Draw something on a canvas and upload as image
const canvas = document.getElementById('someCanvas')
const ctx = canvas.getContext('2d')
ctx.fillStyle = '#f85040'
ctx.fillRect(0, 0, 50, 50)
ctx.fillStyle = '#fff'
ctx.font = '10px monospace'
ctx.fillText('Sanity', 8, 30)
canvas.toBlob(uploadImageBlob, 'image/png')
function uploadImageBlob(blob) {
client.assets
.upload('image', blob, {contentType: 'image/png', filename: 'someText.png'})
.then((document) => {
console.log('The image was uploaded!', document)
})
.catch((error) => {
console.error('Upload failed:', error.message)
})
}
// Extract palette of colors as well as GPS location from exif
client.assets
.upload('image', someFile, {extract: ['palette', 'location']})
.then((document) => {
console.log('The file was uploaded!', document)
})
.catch((error) => {
console.error('Upload failed:', error.message)
})
Deleting an asset document will also trigger deletion of the actual asset.
client.delete(id: string): Promise
client.delete('image-abc123_someAssetId-500x500-png').then((result) => {
console.log('deleted imageAsset', result)
})
const config = client.config()
console.log(config.dataset)
client.config()
Get client configuration.
client.config({dataset: 'newDataset'})
client.config(options)
Set client configuration. Required options are projectId and dataset.
Contentful is a content management platform that provides a similar set of functionalities for managing structured content. It allows you to fetch, create, update, and delete content entries. Compared to @sanity/client, Contentful offers a more traditional CMS experience with a focus on ease of use and integration with various front-end frameworks.
Prismic is another headless CMS that offers a JavaScript client for interacting with its API. It provides functionalities for querying, creating, and managing content. Prismic's API is more RESTful compared to Sanity's GROQ-based querying, and it emphasizes a slice-based content modeling approach.
Strapi is an open-source headless CMS that provides a JavaScript SDK for interacting with its API. It allows you to perform CRUD operations on your content types. Strapi is highly customizable and can be self-hosted, offering more control over the backend compared to Sanity.
FAQs
Client for retrieving, creating and patching data from Sanity.io
The npm package @sanity/client receives a total of 865,775 weekly downloads. As such, @sanity/client popularity was classified as popular.
We found that @sanity/client demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 114 open source maintainers collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
A surge of AI-generated vulnerability reports has pushed open source maintainers to rethink bug bounties and tighten security disclosure processes.

Product
Scan results now load faster and remain consistent over time, with stable URLs and on-demand rescans for fresh security data.

Product
Socket's new Alert Details page is designed to surface more context, with a clearer layout, reachability dependency chains, and structured review.