Javascript client for Contentful's Content Management API:
- API Documentation
- REST API Documentation
- Examples
- Create an access token for the Content Management API (need account)
Supported browsers/environments:
- Chrome
- Firefox
- IE10
- node.js >= 0.8
In node, using npm:
npm install contentful-management
Note: The next minor version release of dist/contentful-management.min.js
will
be much smaller. Please use a package manager to keep your JS
dependencies up to date and get the newest version right when it's
ready!
This library comes with a few example scripts
This clones a Space's complete content model & content. It's intended to be used to create one-time clones of Spaces, not for synchronization.
$ example/clone-space.js \
--access-token $CONTENTFUL_ACCESS_TOKEN \
--source-space-id $SOURCE_SPACE_ID \
--destination-space-id $DESTINATION_SPACE_ID
Omit the destination-space-id
parameter to make the script create a
Space. When doing that you might have to specify a
destination-organization-id
parameter if your user is in multiple
organizations.
If you just want the content types for a space to be cloned, add the --only-content-types
flag.
$ example/clone-space.js \
--access-token $CONTENTFUL_ACCESS_TOKEN \
--source-space-id $SOURCE_SPACE_ID \
--destination-space-id $DESTINATION_SPACE_ID \
--only-content-types
Sometimes you need to migrate content from one field to another. This is a script which migrates all values from one field to another field, using a specific mapping function if it's provided. It'll do this for each entry of a specific Content Type in a Space, going through it slice by slice.
Currently this supports mapping from Text to Symbol. But it would be very simple to convert e.g. numbers to symbols or even location strings to locations by geocoding. PRs are very welcome!
$ example/migrate-fields.js \
--access-token $CONTENTFUL_MANAGEMENT_API_ACCESS_TOKEN \
--space-id $SPACE_ID \
--content-type-id $CONTENT_TYPE_ID \
--source-field-id $SOURCE_FIELD_ID \
--destination-field-id $DESTINATION_FIELD_ID
To use the Content Management API you will need an access token. The easiest way to get a token for local scripts/experimentation is by using the OAuth app embedded in our Developer center documentation.
var contentful = require('contentful-management');
var client = contentful.createClient({
// A valid access token for your user (see above on how to create a valid access token)
accessToken: 'b4c0n73n7fu1',
// Enable or disable SSL. Enabled by default.
secure: true
});
client.getSpace('foobar')
Returns a promise for a Space object.
Create a space with the name 'CMA Example Space'.
client.createSpace({name: 'CMA Example Space'})
Returns a promise for a Space object.
Delete a space and all of it's content. Warning: there is no undo!
client.deleteSpace(space);
Returns a promise for nothing, which should still be checked for errors.
A space is a top level container for all other resources. In addition to the methods documented below, a space has the following data properties:
{
"name": "Example Space",
"sys": {
"type": "Space",
"id": "1vlwe1hnkhmk",
"version": 0,
"createdBy": {
"sys": {
"type": "Link",
"linkType": "User",
"id": "0lEP0wVJL8WSQSbRuVUdcJ"
}
},
"createdAt": "2013-09-22T17:34:53Z",
"updatedBy": {
"sys": {
"type": "Link",
"linkType": "User",
"id": "0lEP0wVJL8WSQSbRuVUdcJ"
}
},
"updatedAt": "2013-09-22T17:34:53Z"
}
}
Create a new content type by providing a name, fields, optional description,
and an optional ID. If you do not provide the sys.id
property, an ID will be
generated for you.
space.createContentType({
sys: {id: 'blog-post'},
name: 'Blog Post',
description: 'For like, blogging',
fields: [
{id: 'title', name: 'Title', type: 'Text'},
{id: 'body', name: 'Body', type: 'Text'}
]
})
The easiest way to find out what field types are available and how to represent them in JSON is to use the content type editor built into the [Contentful app][cf-app]. (Note that you will need administrative privileges for a space to edit content types).
Returns a promise for a ContentType.
Retrieve a content type by it's ID (not it's name). Returns a promise for a ContentType.
Publish a [content type][], making it available for use by [create-entry], as well as visible to the [Content Delivery API][].
space.publishContentType(contentType)
Returns a promise for an updated version of the content type.
Unpublish a [content type][]. This operation is not allowed if there are any entries of this content type (because entries may only be created for published content types). If you wish to delete a content type and all of it's entries, you will need to iterate over the entries and delete them before unpublishing and deleting the content type.
space.unpublishContentType(contentType)
Returns a promise for an updated version of the content type.
Delete a content type, note that the content type must be unpublished (and therefore have no entries) before it can be deleted.
space.deleteContentType(contentType)
Retrieve all content types for the space. Returns a promise for a collection of ContentType objects.
Create a new entry by providing field values and and an optional ID. If you do
not provide the sys.id
property, an ID will be generated for you.
space.createEntry(contentType, {
sys: {id: 'hello-world'},
fields: {
title: {'en-US': 'Hello, World!'},
body: {'en-US': 'Bacon is healthy!'}
}
})
For more information on what is allowed in the fields
property, see [Entry
fields][].
Returns a promise for an Entry.
Retrieve an entry by it's ID. Returns a promise for an Entry.
space.getEntry('hello-world')
Publish an Entry, making it visible to the [Content Delivery API][].
space.publishEntry(entry)
Returns a promise for an updated version of the entry.
Unpublish an Entry, this appears to the [Content Delivery API][] as though the entry was deleted.
space.unpublishEntry(entry)
Returns a promise for an updated version of the entry.
Delete an entry. Note that entries must be unpublished before deleting them.
space.deleteEntry(entry)
Returns a promise for nothing, which should still be checked for errors.
Search & filter all of the entries in a space. The query
parameter should be
an object of querystring key-value pairs. The query examples
section containts more examples of the kinds of queries you can perform.
space.getEntries({content_type: 'blog-post'})
Returns a promise for a collection of Entry objects.
Create a new asset by providing field values and and an optional ID. If you do
not provide the sys.id
property, an ID will be generated for you.
space.createAsset({
sys: {id: 'dinosaurs'},
fields: {
title: {'en-US': 'Dinosaur'},
file: {
'en-US': {
upload: 'http://www.qwantz.com/comics/comic2-2870.png'
}
}
}
})
Returns a promise for an Asset, which must be processed before it can be published.
Process the file for a particular asset & locale. Note that this operation is asynchronous on the Contentful backend; you will receive a successful response before the asset is fully processed.
space.processAssetFile(asset, 'en-US');
Returns a promise for nothing, which should still be checked for errors. In
order to detect when an asset has finished processing, retrieve the asset using
space.getAsset
and test for the presence of asset.fields.file[locale].url
.
Retrieve an asset by it's ID. Returns a promise for an Asset.
space.getAsset('dinosaurs')
Publish an Asset, making it visible to the [Content Delivery API][].
space.publishAsset(asset)
Returns a promise for an updated version of the asset.
Unpublish an Asset, this appears to the [Content Delivery API][] as though the asset was deleted.
space.unpublishAsset(asset)
Returns a promise for an updated version of the asset.
Search & filter all of the assets in a space. The query
parameter should be
an object of querystring key-value pairs. The query examples
section containts more examples of the kinds of queries you can perform.
space.getAssets({'fields.file.url[exists]': false})
Returns a promise for a collection of Asset objects.
Each content type defines a schema for entries in it's fields
array. Every
entry has a corresponding content type, and it's own fields
property, which
is an object. The allowed keys and values in an entries fields
object
correspond to the field ids defined in that entries content type.
A complete content type (the one created in create-content-type) looks like:
{
"name": "Blog Post",
"fields": [
{ "id": "title", "name": "Title", "type": "Text" },
{ "id": "body", "name": "Body", "type": "Text" }
],
"sys": {
"id": "blog-post",
"type": "ContentType",
"space": {
"sys": { "type": "Link", "linkType": "Space", "id": "7daovfk1olns" }
},
"createdAt": "2013-09-22T21:42:00.184Z",
"createdBy": {
"sys": { "type": "Link", "linkType": "User", "id": "0lEP0wVJL8WSQSbRuVUdcJ" }
},
"version": 1,
"updatedAt": "2013-09-22T21:42:00.187Z",
"updatedBy": {
"sys": { "type": "Link", "linkType": "User", "id": "0lEP0wVJL8WSQSbRuVUdcJ" }
}
}
}
An entry is a piece of content containing fields and values. Every entry has a
corresponding content type (denoted by it's sys.contentType
property) that
defines what keys are allowed in it's fields
property, and what types those
keys can contain. Note that field values are always nested in an object whose
keys correspond to the locales available in a space.
{
"fields": {
"title": { "en-US": "Hello, World!" },
"body": { "en-US": "Bacon is healthy!" }
},
"sys": {
"id": "hello-world",
"type": "Entry",
"space": {
"sys": { "type": "Link", "linkType": "Space", "id": "7daovfk1olns" }
},
"createdAt": "2013-09-22T23:05:03.271Z",
"createdBy": {
"sys": { "type": "Link", "linkType": "User", "id": "0lEP0wVJL8WSQSbRuVUdcJ" }
},
"contentType": {
"sys": { "type": "Link", "linkType": "ContentType", "id": "blog-post" }
},
"version": 1,
"updatedAt": "2013-09-22T23:05:03.271Z",
"updatedBy": {
"sys": { "type": "Link", "linkType": "User", "id": "0lEP0wVJL8WSQSbRuVUdcJ" }
}
}
}
An asset is special kind of entry containing metadata for a binary file (e.g. an image or video). Note that asset files have multiple states.
{
"fields": {
"title": { "en-US": "Dinosaurs" },
"file": { "en-US": { /* See comments regarding asset file states below */ } }
},
"sys": {
"id": "dinosaurs",
"type": "Asset",
"space": {
"sys": { "type": "Link", "linkType": "Space", "id": "7daovfk1olns" }
},
"createdAt": "2013-09-22T23:05:03.271Z",
"createdBy": {
"sys": { "type": "Link", "linkType": "User", "id": "0lEP0wVJL8WSQSbRuVUdcJ" }
},
"version": 1,
"updatedAt": "2013-09-22T23:05:03.271Z",
"updatedBy": {
"sys": { "type": "Link", "linkType": "User", "id": "0lEP0wVJL8WSQSbRuVUdcJ" }
}
}
}
Assets may contain references to multiple files (one for each locale of their space) and each one of those files may be in one of three states: "new", "ready to process", or "processed".
To determine the state of an asset file, you can test for the presence of
fields.file[locale].upload
and fields.file[locale].url
. If the url
property is set, then the file has already been processed. If the url
property
is not set, but the upload
property is, you can attempt processing of the
file.
If neither property is present, the upload
property must be set to a valid
publically accessible URL before calling Space#processAssetFile.
Note that an asset with unprocessed files can not be published.
You can filter & search the entries and assets in your space by passing query
params to Space#getEntries
and Space#getAssets
. There are
a few predefined query parameter names (such as content_type
and order
), and
you can also query against document properties by using a dot-separated property
path (followed by an optional operator in square brackets) as a query parameter
name.
For example: fields.name[ne]
means "entries where fields.name
is not-equal
to ...". Full documentation of the allowed query parameters & field operators
can be found in our API Documentation, but below are some
examples of common queries to get you started:
Search entries that have been updated since the 1st of January, 2013:
space.getEntries({ 'sys.updatedAt[gte]': '2013-01-01T00:00:00Z' })
Retrieve a specific set of entries by their sys.id
:
space.getEntries({ 'sys.id[in]': [ 'finn', 'jake' ] })
Search for cat
entries that have less than three lives left:
space.getEntries({
'content_type': 'cat',
'fields.lives[lt]': 3
})
Specifying the
content_type
query parameter is required when querying on fields (such asfields.lives
above). Note that'cat'
is the content type ID and not it's name.
Full-text search for entries with "bacon" anywhere in their textual content:
space.getEntries({ query: 'bacon' })
Full-text search for dogs with "bacon" specifically in the description
field:
space.getEntries({
'content_type': 'dog',
'fields.description[match]': 'bacon'
})
Get the 50 most recently created entries, and the next 50:
space.getEntries({
order: '-sys.createdAt',
limit: 50
})
space.getEntries({
order: '-sys.createdAt',
skip: 50,
limit: 50
})
See also: Collections and pagination.
Many methods return collections of resources. These collections are represented as a JSON object containing items and pagination details:
{
"sys": {
"type": "Array"
},
"total": 1, // Total number of items matching the query
"skip": 0, // Offset into the result set represented by this response
"limit": 100, // Effective limit on # of items returned in this response
"items": [
// Full representations of each item
]
}
The getEntries
and getAssets
methods both accept limit
, skip
, and
order
as query parameters, allowing you to paginate through larger result
sets. Note that specifying a stable property (such as 'sys.createdAt'
) for
ordering results is recommended.
Set the following environment variables to valid values:
CONTENTFUL_ACCESS_TOKEN
- a valid access token valueCONTENTFUL_MANAGEMENT_HOSTNAME
- the Contentful host name (without protocol)
Then execute the unit tests:
npm test
MIT