A utility library for the Contentful Management API 🔗, designed to help developers interact with the API in a more intuitive and streamlined way. This library provides functions for common tasks, such as retrieving and publishing entries, as well as tools for handling errors and logging.
Sponsored by Atida
✨ Features · 💡 Installation · 📟 Example · 🎹 Usage · 🔊 verbosityLevel · 📅 ToDo · 👾 Contributors · 🎩 Acknowledgments · 📚 Collection · 📄 License
- Easy-to-use functions for common tasks
- Compatible return types with CMA
- Customizable verbosity level for console logging
- Robust error handling and validation
- Async/await API for easy integration into async workflows
To use this helper library, you must have NodeJS 🔗 and npm 🔗 installed.
To install it, simply run:
npm install contentful-lib-helpers --save
Or, if using yarn 🔗:
yarn add contentful-lib-helpers
Similarly, if you are using Bun 🔗, just run
bun add contentful-lib-helpers
node
>= 18.20.0npm
>= 10.5.0contentful-management
>= 11.31.7
Here a simple example of writing a function that finds an entry by slug, add a tag and then republishes it.
We show both implementations: one using only the Contentful Management SDK and the other one, much shorter, using the Contentful Lib Helpers.
With Contentful Lib Helpers
(async function main () {
const contentfulManagement = require('contentful-management')
const lib = await import('contentful-lib-helpers')
const environment = await lib.getEnvironment(
contentfulManagement,
'your-access-token',
'your-space-id',
'master'
)
const entryId = await lib.getEntryIdByUniqueField(
environment,
'page',
'slug',
'/my-awesome-blog-post'
)
if (entryId) {
await lib.addEntryTag(environment, entryId, 'your-tag')
await lib.publishEntry(environment, entryId)
}
})()
Only with Contentful Management SDK
(async function main () {
const contentfulManagement = require('contentful-management')
const client = await contentfulManagement.createClient({
accessToken: 'your-access-token',
})
try {
// Get the environment
const space = await client.getSpace('your-space-id')
const environment = await space.getEnvironment('master')
// Get the entry ID by unique field
const entry = await environment.getEntries({
content_type: 'page',
['fields.slug']: '/my-awesome-blog-post',
limit: 1
})
const entryId = entry.items.length > 0 ? entry.items[0].sys.id : null
if (entryId) {
// Add tag to the entry
const tagName = 'country-it'
const entryWithTags = await environment.getEntry(entryId).then((entry) => {
entry.metadata = entry.metadata || { tags: [] }
if (!entry.metadata.tags.includes(tagName)) {
entry.metadata.tags.push({
sys: {
type: 'Link',
linkType: 'Tag',
id: tagName
}
})
}
return entry
})
await entryWithTags.update()
// Publish the entry with tag
const publishedEntry = await environment.getEntry(entryId).then((entry) => {
entry.metadata = entry.metadata || {}
entry.metadata.tags = entry.metadata.tags || []
return entry.publish()
})
console.log(`Published entry with ID ${publishedEntry.sys.id} and tag ${tagName}`)
} else {
console.error(`Entry not found`)
}
} catch (error) {
console.error(`Error: ${error.message}`)
}
})()
Two alternative ways to include the Contentful library as ES Module are the following:
// At the beginning of the file
import contentfulManagement from 'contentful-management'
// Inside a function
const { default: contentfulManagement } = await import('contentful-management')
// If you are using Bun.sh
const contentfulManagement = await import('contentful-management')
See also: NodeJS modules import 🔗
Here are the methods available in this library and how to use them:
Space/Environment
Content-types/Entries
- getContentTypes
- getContentType
- getAllEntriesByContentType
- getEntryIdByUniqueField
- getEntry
- extractStatusFromSys
- publishEntry
- unpublishEntry
Tags
Locales
Release
The function retrieves a Contentful space object by its ID, using the Contentful Management API.
contentfulManagement
- The Contentful Management library.contentfulToken
- The Contentful access token.contentfulSpaceId
- The ID of the space to retrieve.verbosityLevel
- (optional, default1
) the level of console logging verbosity to use. See verbosityLevel.
The function returns a Promise that resolves with the Space object, or null if not found.
import { getSpace } from 'contentful-lib-helpers'
import contentfulManagement from 'contentful-management'
const contentfulToken = 'your-access-token'
const contentfulSpaceId = 'your-space-id'
const space = await getSpace(
contentfulManagement,
contentfulToken,
contentfulSpaceId,
2
)
console.log(space)
{
name: 'Contentful Test Space',
sys: {
type: 'Space',
id: 'your-space-id',
version: 2,
createdBy: { sys: [Object] },
createdAt: '2023-03-31T10:41:25Z',
updatedBy: { sys: [Object] },
updatedAt: '2023-03-31T10:42:41Z',
organization: { sys: [Object] }
}
}
The function retrieves a Contentful environment object by ID, using the Contentful Management API.
contentfulManagement
- The Contentful Management library.contentfulToken
- The Contentful access token.contentfulSpaceId
- The ID of the space to retrieve.contentfulEnvironmentId
- The ID of the environment to retrieve (defaultmaster
).verbosityLevel
- (optional, default1
) the level of console logging verbosity to use. See verbosityLevel.
The function returns a Promise that resolves with the Environment object, or null if not found.
import { getEnvironment } from 'contentful-lib-helpers'
import contentfulManagement from 'contentful-management'
const contentfulToken = 'your-access-token'
const contentfulSpaceId = 'your-space-id'
const contentfulEnvironmentId = 'your-environment-id'
const environment = await getEnvironment(
contentfulManagement,
contentfulToken,
contentfulSpaceId,
contentfulEnvironmentId,
2
)
console.log(environment)
{
name: 'master',
sys: {
type: 'Environment',
id: 'master',
version: 3,
space: { sys: [Object] },
status: { sys: [Object] },
createdBy: { sys: [Object] },
createdAt: '2023-04-04T15:13:55Z',
updatedBy: { sys: [Object] },
updatedAt: '2023-04-04T15:13:56Z',
aliases: []
}
}
The function retrieves get all Content-types in a Contentful environment.
environment
- Environment Object (you can retrieve it with getEnvironment).verbosityLevel
- (optional, default1
) the level of console logging verbosity to use. See verbosityLevel.
The function returns a Promise that resolves with a Content-type collection if successful, or an empty Collection otherwise.
Note: the decision to return an empty collection, is because collections of any kind are usually looped trough. If we would be returning a null
/false
value, that would need to be verified before looping through the elements. With the empty collection, the items can be passed to the loop (that won't loop because empty).
const allContentTypes = await getContentTypes(
environment,
2
)
console.log(allContentTypes)
{
sys: { type: 'Array' },
total: 3,
skip: 0,
limit: 100,
items: [
{
sys: [Object],
displayField: 'key',
name: 'Translation',
description: '',
fields: [Array]
},
{
...
},
{
...
}
]
}
The function retrieves a Content-type object by its ID.
environment
- Environment Object (you can retrieve it with getEnvironment).contentTypeId
- The ID of the content-type to retrieve.verbosityLevel
- (optional, default1
) the level of console logging verbosity to use. See verbosityLevel.
The function returns a Promise that resolves with the content-type object if it exists, or null
otherwise.
const contentType = await getContentTypes(
environment,
'translation',
2
)
console.log(contentType)
{
sys: {
space: { sys: [Object] },
id: 'translation',
type: 'ContentType',
createdAt: '2023-03-31T11:12:04.950Z',
updatedAt: '2023-03-31T11:18:19.563Z',
environment: { sys: [Object] },
publishedVersion: 13,
publishedAt: '2023-03-31T11:18:19.563Z',
firstPublishedAt: '2023-03-31T11:12:05.422Z',
createdBy: { sys: [Object] },
updatedBy: { sys: [Object] },
publishedCounter: 7,
version: 14,
publishedBy: { sys: [Object] }
},
displayField: 'key',
name: 'Translation',
description: '',
fields: [
{
id: 'key',
name: 'key',
type: 'Symbol',
localized: false,
required: true,
validations: [Array],
disabled: false,
omitted: false
},
{
id: 'value',
name: 'value',
type: 'Symbol',
localized: true,
required: true,
validations: [],
disabled: false,
omitted: false
}
]
}
It gets a Collection of all the Contentful Entries, by Content-type. The peculiarity of this method is that does the pagination (default 1000 elements) for you, and the returned collection contains all the entries.
environment
- Environment Object (you can retrieve it with getEnvironment).contentTypeId
- The ID of the content-type to retrieve.limit
- Number of entries to retrieve at each loop. Default1000
.verbosityLevel
- (optional, default1
) the level of console logging verbosity to use. See verbosityLevel.
The function returns a Promise that resolves with a Collection of Contentful Entries, or an empty Collection otherwise.
Note: the decision to return an empty collection, is because collections of any kind are usually looped trough. If we returned a null
/false
value, that would need to be verified before looping through the elements. With the empty collection, the items can be passed to the loop (that won't loop because empty).
const allEntries = await getAllEntriesByContentType(
environment,
'translation',
1000,
2
)
console.log(allEntries)
{
sys: { type: 'Array' },
total: 5,
skip: 0,
limit: 5,
items: [
{ metadata: [Object], sys: [Object], fields: [Object] },
{ metadata: [Object], sys: [Object], fields: [Object] },
{ metadata: [Object], sys: [Object], fields: [Object] },
{ metadata: [Object], sys: [Object], fields: [Object] },
{ metadata: [Object], sys: [Object], fields: [Object] }
]
}
Find an Entry in a specific Content Type and locale by its unique identifier field.
environment
- Environment Object (you can retrieve it with getEnvironment).fieldId
- The ID of the unique field to search for. A unique field is usually a mandatory and unique field in the Content-type (ie: slug).fieldValue
- The value to search for in the unique field.fieldLocale
- The locale to search in for the unique field. If not provided, the default locale will be used.verbosityLevel
- (optional, default1
) the level of console logging verbosity to use. See verbosityLevel.
A Promise that resolves to the Entry ID or null
otherwise. We can then use getEntry to retrieve the Entry itself.
const entryId = await getEntryIdByUniqueField(
environment,
'translation',
'key',
'test.entry'
)
console.log(entryId)
AKjzIrXfTQFS6oXjJp71Z
Get a Contentful entry by ID.
environment
- Environment Object (you can retrieve it with getEnvironment).entryId
- The ID of the entry to get.verbosityLevel
- (optional, default1
) the level of console logging verbosity to use. See verbosityLevel.
A Promise that resolves with the entry object, or null
if not found.
const entry = await getEntry(
environment,
'exampleEntryId',
2
)
console.log(entry)
{
metadata: { tags: [] },
sys: {
space: { sys: [Object] },
id: 'GKjzIfXfTQFS8oXjJp71Y',
type: 'Entry',
createdAt: '2023-04-04T15:11:47.018Z',
updatedAt: '2023-04-04T17:19:50.990Z',
environment: { sys: [Object] },
firstPublishedAt: '2023-04-04T17:19:25.915Z',
createdBy: { sys: [Object] },
updatedBy: { sys: [Object] },
publishedCounter: 2,
version: 9,
automationTags: [],
contentType: { sys: [Object] }
},
fields: { key: { 'en-US': 'test.entry' }, value: { 'en-US': 'Test' } }
}
The function extracts the status of a Contentful Entry from its sys
properties.
entrySys
- The sys properties of the Entry.
It returns the status of an Entry: published
, changed
, draft
and archived
(in the unlikely possibility of an error, it would return unknown
).
const entry = await getEntry(
environment,
'exampleEntryId'
)
const entryStatus = await extractStatusFromSys(entry?.sys)
console.log(entryStatus)
published
Publishes a Contentful entry.
environment
- Environment Object (you can retrieve it with getEnvironment).entryId
- The ID of the entry to publish.verbosityLevel
- (optional, default1
) the level of console logging verbosity to use. See verbosityLevel.
A Promise that resolves with true
if the entry was published successfully, or false
otherwise.
const isEntryPublished = await publishEntry(
environment,
'exampleEntryId',
2
)
console.log(isEntryPublished)
true
Unpublishes a Contentful Entry.
environment
- Environment Object (you can retrieve it with getEnvironment).entryId
- The ID of the entry to unpublish.verbosityLevel
- (optional, default1
) the level of console logging verbosity to use. See verbosityLevel.
Promise that resolves with true
if the entry was unpublished successfully, or false
otherwise.
const isEntryUnpublished = await unpublishEntry(
environment,
'exampleEntryId',
2
)
console.log(isEntryUnpublished)
true
The function checks if a tag exists in a Contentful environment.
environment
- Environment Object (you can retrieve it with getEnvironment).tagId
- The ID of the tag to check.verbosityLevel
- (optional, default1
) the level of console logging verbosity to use. See verbosityLevel.
A Promise that resolves with true
if the tag exists, or false
otherwise.
const tagExists = await getTagExists(
environment,
'country-en',
2
)
console.log(tagExists)
true
Adds a tag to a Contentful Entry.
environment
- Environment Object (you can retrieve it with getEnvironment).entryId
- he ID of the entry to add the tag to.tagId
- The ID of the tag to add.verbosityLevel
- (optional, default1
) the level of console logging verbosity to use. See verbosityLevel.
A Promise that resolves with true
if the tag was added successfully, or false
otherwise.
Note: the entry will need to be republished, after the tag is added. See publishEntry.
const isTagAdded = await addEntryTag(
environment,
'exampleEntryId',
'exampleTagId',
2
)
console.log(isTagAdded)
true
Removes a tag to a Contentful Entry.
environment
- Environment Object (you can retrieve it with getEnvironment).entryId
- he ID of the entry to remove the tag from.tagId
- The ID of the tag to remove.verbosityLevel
- (optional, default1
) the level of console logging verbosity to use. See verbosityLevel.
A Promise that resolves with true
if the tag was removed successfully, or false
otherwise.
Note: the entry will need to be republished, after the tag is removed. See publishEntry.
const isTagRemoved = await addEntryTag(
environment,
'exampleEntryId',
'exampleTagId',
2
)
console.log(isTagRemoved)
true
The function deletes the given Contentful environment, unless it is protected.
environment
- Environment Object (you can retrieve it with getEnvironment).verbosityLevel
- (optional, default1
) the level of console logging verbosity to use. See verbosityLevel.forbiddenEnvironments
- An array of environment IDs that are protected and cannot be deleted. Default protected environments:master
,staging
,uat
,dev
.
Note: the function has the verbosityLevel
as second parameter, instead of the last one. This is to allow using the default value for forbiddenEnvironments
, hence protecting the production and testing environments.
The function returns true if the environment was successfully deleted, false otherwise.
import { getEnvironment, deleteEnvironment } from 'contentful-lib-helpers'
import contentfulManagement from 'contentful-management'
const contentfulToken = 'your-access-token'
const contentfulSpaceId = 'your-space-id'
const contentfulEnvironmentId = 'environment-to-delete'
const environment = await getEnvironment(
contentfulManagement,
contentfulToken,
contentfulSpaceId,
contentfulEnvironmentId,
2
)
const isEnvironmentDeleted = await deleteEnvironment(
environment,
2,
['master', 'staging', 'dev']
)
console.log(isEnvironmentDeleted)
true
Get all locales for a given environment.
environment
- Environment Object (you can retrieve it with getEnvironment).verbosityLevel
- (optional, default1
) the level of console logging verbosity to use. See verbosityLevel.
A Collection of Locale objects.
const allLocales = await getAllLocales(
environment,
2
)
console.log(allLocales)
{
sys: { type: 'Array' },
total: 2,
skip: 0,
limit: 100,
items: [
{
name: 'English (United States)',
code: 'en-US',
fallbackCode: null,
default: true,
contentManagementApi: true,
contentDeliveryApi: true,
optional: false,
sys: [Object]
},
{
name: 'Italian (Italy)',
code: 'it-IT',
fallbackCode: 'en-US',
default: false,
contentManagementApi: true,
contentDeliveryApi: true,
optional: true,
sys: [Object]
}
]
}
Get all the locale codes, as an array of strings (ie: ['en-US', 'it-IT']
)
environment
- Environment Object (you can retrieve it with getEnvironment).verbosityLevel
- (optional, default1
) the level of console logging verbosity to use. See verbosityLevel.
An array of locale codes.
const allLocalesCode = await getAllLocalesCode(
environment,
2
)
console.log(allLocalesCode)
[ 'en-US', 'it-IT' ]
The function returns the default Locale object.
environment
- Environment Object (you can retrieve it with getEnvironment).verbosityLevel
- (optional, default1
) the level of console logging verbosity to use. See verbosityLevel.
The function returns the locale object of the default locale of the Contentful environment.
const defaultLocale = await getDefaultLocale(
environment,
2
)
console.log(defaultLocale)
{
name: 'English (United States)',
code: 'en-US',
fallbackCode: null,
default: true,
contentManagementApi: true,
contentDeliveryApi: true,
optional: false,
sys: {
type: 'Locale',
id: '3XPgmbnnEyfxxtHVQlcfki',
version: 1,
space: { sys: [Object] },
environment: { sys: [Object] },
createdBy: { sys: [Object] },
createdAt: '2023-04-04T15:13:55Z',
updatedBy: { sys: [Object] },
updatedAt: '2023-04-04T15:13:55Z'
}
}
The function returns the default Locale code (ie: en-US
).
environment
- Environment Object (you can retrieve it with getEnvironment).verbosityLevel
- (optional, default1
) the level of console logging verbosity to use. See verbosityLevel.
The function returns default locale code, as a string.
const defaultLocaleCode = await getDefaultLocaleCode(
environment,
2
)
console.log(defaultLocaleCode)
en-US
This is a very particular function. Passing a 'default' value, that can be anything (null
, boolean, string, etc), it returns an object whose keys are the locales, and the values are the default value passed.
This is used by our other NPM package Contentful CLI Migrations, to build locale-agnostic migrations. Meaning that the locales don't need to be hard-coded when setting up default values in a Contentful Javascript migration.
environment
- Environment Object (you can retrieve it with getEnvironment).defaultValue
- It can be a value of any type (usuallynull
, empty string''
or a boolean valuetrue/false
)
The function returns an object whose keys are the locales and the values are the default value passed.
const objectDefaultValues = await getDefaultValuesForLocales(
environment,
true
)
console.log(objectDefaultValues)
{ 'en-US': true, 'it-IT': true }
Given a source Environment id (ie: master
), it creates a duplicated with a new Environment id. The duplication does not 'copy' the Scheduled Content, for which you will need to use the method syncScheduledActions.
space
- Differently from other methods, it uses the Space Object (you can retrieve it with getSpace).sourceEnvironmentId
- The source environment that will be duplicated (default:master
).destinationEnvironmentId
- The ID/Name of the new environment.verbosityLevel
- (optional, default1
) the level of console logging verbosity to use. See verbosityLevel.
The function returns an Environment object that can be queried or manipulated to perform further actions.
const newEnvironment = await duplicateEnvironment(
space,
'master',
'release-1.25.5',
3
)
console.log(newEnvironment)
{
name: 'release-1.25.5',
sys: {
type: 'Environment',
id: 'release-1.25.5',
version: 1,
space: { sys: [Object] },
status: { sys: [Object] },
createdBy: { sys: [Object] },
createdAt: '2023-07-24T14:19:26Z',
updatedBy: { sys: [Object] },
updatedAt: '2023-07-24T14:19:26Z',
aliases: []
}
}
This function is needed when we want to enable an Environment for a particular CDA Key. For example a duplicate of the master
Environment will need the same CDA Key that is used to query the current master.
Note: It's a good habit to name the CDA Key with the same name as the Environment. This because the API can query the Key only by name. So it is recommended to a be a lowercase name without punctuation or spaces.
space
- Differently from other methods, it uses the Space Object (you can retrieve it with getSpace).cdaKeyName
- The 'name' of the CDA Key. Usually should match an environment name. Recommended to use lowercase, no punctuation and no spaces.targetEnvironmentId
- The Environment id for which the CDA Key will be enabled.verbosityLevel
- (optional, default1
) the level of console logging verbosity to use. See verbosityLevel.
true
if the CDA Key has been enabled. false
otherwise.
const enabledCdaKey = await enableCdaKey(
space,
'master',
'release-1.25.5',
3
)
console.log(enabledCdaKey)
true
Given an Environment id and and Alias, it links the Alias to that Environment. This function has to be used to switch, for example the current master
alias to a new release Envirionment.
space
- Differently from other methods, it uses the Space Object (you can retrieve it with getSpace).sourceEnvironmentId
- The ID of the source Environment that will be linked.destinationEnvironmentId
- The ID of the Alias to which the Environment will be linked to.releaseRegEx
- Regular expression to identify release Environments.protectedEnvironments
- Safety measure when deleting old release to not deleted important Environments.deleteOldReleases
- If true, it deletes all release Environments, except the newly linked one and the previous one.verbosityLevel
- (optional, default1
) the level of console logging verbosity to use. See verbosityLevel.
The function does not return any value, but it does return a detailed error message in case of failure.
await linkAliasToEnvironment(
space,
'release-1.25.5',
'master'
)
When duplicating an Environment, the Scheduled Actions are not usually carried over. This function copies those Scheduled Actions between two environments.
space
- Differently from other methods, it uses the Space Object (you can retrieve it with getSpace).sourceEnvironmentId
- The source environment that contains the Scheduled Actions.destinationEnvironmentId
- The destination environment to which those Actions will be copied to.verbosityLevel
- (optional, default1
) the level of console logging verbosity to use. See verbosityLevel.
The function does not return any value, but it does return a detailed error message in case of failure.
await syncScheduledActions(
space,
'master',
'release-1.25.5',
3
)
All methods accept an optional verbosityLevel parameter. This parameter is an integer from 0 to 3 that determines the amount of console logging the function should output. A higher number means more logging. The default value is 1 (error logging)
0
- No logging.1
- Only errors.2
- Errors and debug information.3
- All logs, including info logs.
- Add further methods (ie:
getAllAssets
,uploadAsset
, ...) - Improve Logging (+ Colors).
- Add Tests
- Add Support for Yargs and Chalk
@fciacchi |
@psyvic |
@aalduz |
@leslyto |
Feel free to open issues or pull requests in our GitHub Repository if you have suggestions or improvements to propose.
I would like to express my gratitude to the following parties:
- Atida 🔗, the company that has allowed these scripts to be open sourced. Atida is an e-commerce platform that sells beauty and medical products. Their support for open source is greatly appreciated. A special thank to Shaya Pourmirza that has been a great promoter and supporter of this initiative inside the company.
- Contentful 🔗, for creating their excellent content management platform and the JavaScript CMA SDK that this library is built on. Without their work, this project would not be possible.
Thank you to everyone involved!
We produce a bunch of interesting packages for Contentful. You might want to check them out:
- Contentful Lib Helpers (GitHub and NpmJS): Utility Library for Contentful Management API.
- Contentful CLI Export (GitHub and NpmJS): Simplifies backup of your Contentful Environment.
- Contentful CLI Migrations (GitHub and NpmJS): Tool to automate and scale Contentful Migrations.
- Contentful CLI Release (GitHub and NpmJS): Release utilities to deploy Contentful in a CI/CD.
This project is licensed under the MIT License