Web Service API
Getting started with the Web Service API
This example shows how to use the Web Service API.
Authenticating
To access content with the service, you need an authentication token. To get one, post a JSON payload with credentials to the authentication service (part of the permission service).
login.json:
{
"username" : "admin",
"password" : "123456"
}
$ curl --request POST \
--header 'Content-Type: application/json' \
--data @login.json \
'http://ace-content-service:8081/security/token'
or like this:
$ curl --request POST \
--header "Content-Type: application/json" \
--data '{"username":"admin", "password":"123456"}' \
'http://ace-content-service:8081/security/token'
HTTP response:
{
"token": "...",
"userId": "admin",
"expireTime": "1511376976000",
"renewTime": "1511373376000"
}
- token: the token issued by the authentication request
- userId: the ID of the user for which the token is issued
- expireTime: the time when the issued token becomes invalid
- renewTime: a suggested time for when a client should try renewing the token
The format of expireTime and renewTime is Epoch/Unix timestamp
expressed using millisecond resolution.
The token should be included in the X-Auth-Token HTTP header for ACE service requests.
To simplify further examples, let's store it in a shell variable:
export TOKEN="..."
Authenticating with an AWS Cognito token
login.json:
{
"token" : "[AWS COGNITO TOKEN...]"
}
$ curl --request POST \
--header 'Content-Type: application/json' \
--data @login.json \
'http://ace-content-service:8081/security/token'
HTTP response:
{
"token": "...",
"userId": "admin",
"expireTime": "1511376976000",
"renewTime": "1511373376000"
}
Renewing Token
To avoid having to login in with the username and password, it is possible get a new token using the the username and the current token, as long as the current token is valid. To renew, post a JSON payload with username and token (to be renewed) to the token service.
$ curl --request POST \
--header "Content-Type: application/json" \
--data {"username":"admin","token":"$TOKEN"} \
'http://ace-content-service:8081/security/token'
The response contains the new token, user ID, expiry time and the renewal time.
HTTP response:
{
"token": "...",
"userId": "admin",
"expireTime": "1511384988000",
"renewTime": "1511381388000"
}
Creating content
To create content, POST json to the content service. Do not forget content type and authorization headers.
article.json:
{
"system": {
"contentType": "doc_example_content"
},
"aspects": {
"doc_example": {
"title": "Hello, world!"
}
}
}
Request:
$ curl --request POST \
--header "Content-Type: application/json" \
--header "X-Auth-Token: $TOKEN" \
--data @article.json \
'http://ace-content-service:8081/content'
Response:
{
"system": {
"id": "contentid/ZGU5YzViMzctNDM5My00",
"version": "c:MTY4M2ZlNDktMjNkYy00:MTBmMTc5",
"modificationTime": "2020-03-25T12:47:57.763Z",
"creationTime": "2020-03-25T12:47:57.763Z",
"contentType": "doc_example_content"
},
"aspects": {
"_type": "doc_example_content",
"doc_example": {
"_type": "doc_example",
"title": "Hello, world!"
}
},
"status": {
"message": "CREATED",
"statusCode": "20100",
"extraInfo": {}
}
}
Reading content
To retrieve a content, issue a GET request. When a request is issued to an unversioned content ID, the service responds with a redirect, so we must give the -L/--location option to curl:
$ curl --location \
--include \
--header "X-Auth-Token: $TOKEN" \
'http://ace-content-service:8081/content/alias/contentid/ZGU5YzViMzctNDM5My00'
HTTP response:
HTTP/1.1 200 OK
Date: Wed, 22 Nov 2017 14:52:44 GMT
Ace-Api-Version: 0.9.17
Cache-Control: private, no-transform, proxy-revalidate, max-age=31536000
ETag: W/"c:MTY4M2ZlNDktMjNkYy00/0"
Content-Type: application/json;charset=utf-8
Content-Length: 446
{
"system": {
"id": "contentid/ZGU5YzViMzctNDM5My00",
"version": "c:MTY4M2ZlNDktMjNkYy00:MTBmMTc5",
"modificationTime": "2017-11-22T13:33:29.990Z",
"creationTime": "2017-11-22T13:33:29.990Z",
"contentType": "doc_example_content"
},
"aspects": {
"_type": "doc_example_content",
"doc_example": {
"_type": "doc_example",
"title": "Hello, world!"
}
},
"status": {
"message": "OK",
"statusCode": "20000",
"extraInfo": {}
}
}
Updating content
To update the content, you can send the same format back using PUT (although the id, version and meta fields will be ignored). Any aspects which you don't want to update may be omitted. You must also include an If-Match header that matches the ETag from the latest version, to make sure you don't accidentally overwrite someone else's changes.
ETag from From get-response:
$ export='W/"c:MTY4M2ZlNDktMjNkYy00/0"'
update.json:
{
"system": {
"id": "contentid/ZGU5YzViMzctNDM5My00",
"version": "c:MTY4M2ZlNDktMjNkYy00:MTBmMTc5",
"modificationTime": "2020-03-25T12:47:57.763Z",
"creationTime": "2020-03-25T12:47:57.763Z",
"contentType": "doc_example_content"
},
"aspects": {
"doc_example": {
"_type": "doc_example",
"title": "Hej, världen!"
}
}
}
Request:
curl --location \
--header "X-Auth-Token: $TOKEN" \
--header "Content-Type: application/json" \
--header "If-Match: $ETAG" \
--request PUT \
--data @update.json \
'http://ace-content-service:8081/content/alias/contentid/ZGU5YzViMzctNDM5My00'
HTTP response
{
"system": {
"id": "contentid/ZGU5YzViMzctNDM5My00",
"version": "c:MTY4M2ZlNDktMjNkYy00:MTBmMTc5",
"modificationTime": "2017-11-22T15:00:59.055Z",
"creationTime": "2017-11-22T13:33:29.990Z",
"contentType": "doc_example_content"
},
"aspects": {
"_type": "doc_example_content",
"doc_example": {
"_type": "doc_example",
"title": "Hej, världen!"
}
},
"status": {
"message": "OK",
"statusCode": "20000",
"extraInfo": {}
}
}
Update modes
By default when a content is updated, aspects that are included in the
request are replaced, and aspects that are not included are left as
in the previous version. This mode is called update, and there are
two other modes that can be used when updating: replace
and merge. The update mode is selected by setting the query parameter updateMode.
In the merge mode, aspects included in the update are patched rather
than replaced them, while still leaving other
aspects untouched. List values will contain the elements from the
previous version with new elements added to the end. Primitive
values will overwrite the previous value. Object values are
recursively merged with old object value, if there was one.
In the replace mode, the new version will be exactly as specified in the update, so aspects
that are not included in the update are removed from the new version.
Deleting content
To delete content, simply issue a DELETE request to the content's URI using one of it's aliases:
Request:
$ curl --include \
--request DELETE \
--header "X-Auth-Token: $TOKEN" \
--header "If-Match: $ETAG" \
'http://ace-content-service:8081/content/alias/contentid/ZGU5YzViMzctNDM5My00'
Response:
HTTP/1.1 204 No Content
Date: Thu, 23 Nov 2017 15:13:09 GMT
Ace-Api-Version: 0.9.17
If the delete is successful, the response will have a 200 OK or 204 No Content status code. Deletes require an If-Match header and will fail with a 400 Bad Request if there is no such header. If the content does not exist the response will be 404 Not Found. If the If-Match doesn't match the latest version of the content the response will be 409 Conflict. If the user does not have permission to delete the content the response will be 403 Forbidden.
A delete is considered successful if the content is no longer retrievable from the data store. This does not necessarily imply that all aspects of the content have been deleted. There is currently no way to distinguish between a full success where everything was deleted or a partial success.
Releasing an Alias
Releasing an Alias means telling the system to no longer associate it with any content.
Warning: Aliases are to be treated as immutable – once an alias has been assigned to a content it should always refer to that content. This also applies to deleted content. Releasing an Alias is a dangerous operation that could cause dangling references and cache issues. An Alias should only be released if there are no references to it or your business logic explicitly handles dangling references.
Only users with role sysadmin in context __global__ are allowed to release Aliases.
A main alias can not be released without first deleting the content.
Tip: Instead of releasing an Alias, consider assigning a new Alias and start referring to that instead.
An Alias is released by issuing a DELETE request to endpoint /content/alias/{alias}/release:
Request:
$ curl --include \
--header "X-Auth-Token: $TOKEN" \
--request DELETE \
'http://localhost:8081/content/alias/{alias}/release'
Response:
HTTP/1.1 204 No Content
Date: Wed, 20 Jun 2018 07:22:29 GMT
Ace-Api-Version: 0.9.21
If the alias does not exist:
Request:
$ curl --include \
--header "X-Auth-Token: $TOKEN" \
--request DELETE \
'http://localhost:8081/content/alias/not/existing/release'
Response:
HTTP/1.1 200 OK
Date: Wed, 20 Jun 2018 07:23:04 GMT
Ace-Api-Version: 0.9.21
Content-Length: 0
Workspace
$ curl -H"X-Auth-Token: $TOKEN" \
-H'Content-Type: application/json' \
http://localhost:8081/content/workspace/{workspacename} \
-d json.json \
The normal content endpoints (create, update, get, delete etc) with added workspace/name_of_workspace will go to the worspace service. A get on this endpoint will get from main storage if no workspace version exist, otherwise get the workspace version.
json.json is a usual content json, no different than any other content json.
{
"system": {
"id": "contentid/ZGU5YzViMzctNDM5My00",
"version": "draft:MTY4M2ZlNDktMjNkYy00:WORKSPACE-workspace1",
"modificationTime": "2017-12-19T14:17:04.536Z",
"creationTime": "2017-12-19T14:17:04.536Z",
"contentType": "com.atex.ace.content.AspectBeanContent"
},
"aspects": {
"_type": "com.atex.ace.content.AspectBeanContent",
"com.atex.ace.content.AspectBean": {
"_type": "com.atex.ace.content.AspectBean",
"name": "Example",
"value": "Value"
}
},
"operations": [],
"status": {
"message": "CREATED",
"statusCode": "20100",
"extraInfo": {}
}
}
The data format
The data format produced by the Content API service is a Data Shuttle structured in JSON, wrapped in an envelope containing metadata.
Example:
{
"system": {
"id": "contentid/ZGU5YzViMzctNDM5My00",
"version": "c:MTY4M2ZlNDktMjNkYy00:MTBmMTc5",
"modificationTime": "2017-11-22T15:00:59.055Z",
"creationTime": "2017-11-22T13:33:29.990Z",
"contentType": "doc_example_content"
},
"aspects": {
"_type": "doc_example_content",
"doc_example": {
"_type": "doc_example",
"title": "Hej, världen!"
}
},
"status": {
"message": "OK",
"statusCode": "20000",
"extraInfo": {}
}
}
Fields:
| Name | Value |
|---|---|
| system/id | The content's main alias |
| system/version | The content version id |
| system/creationTime | Timestamp (UTC) in Instant ISO-8601 representation for when the first version of the content was created |
| system/modificationTime | Timestamp (UTC) in Instant ISO-8601 representation for when this content version was created |
| system/contentType | The content's content type |
| data | The content's data as a map of aspects |
| data/my_aspect/* | Data fields for the aspect called 'my_aspect' |
Formats
The format of the response can be specified using the format query parameter or the Accept header.
| Format | Parameter | Accept Header | Content-Type |
|---|---|---|---|
| JSON | json | application/json | application/json |
| Pretty Print JSON | json+pretty | application/json;pretty=true | application/json |
| Fully typed JSON | json+allTypes | application/json;allTypes=true | application/json |
HTTP response status codes
The Content API REST service uses HTTP status codes to indicate success or failure of operations. When an error occurs, a special response body format is also used (see below).
| Status code | Reason |
|---|---|
| 200 OK | Everything is just fine. |
| 303 See other | Used when resolving symbolic (unversioned or external) ids. Forms the basis for a redirect together with the provided Location header. |
| 304 Not modified | Nothing has changed, no need to fetch the content again. See below for details. |
| 401 Unauthorized | This actually means that you are not authenticated. |
| 403 Forbidden | Permission denied. |
| 404 Not found | Content was not found. |
| 409 Conflict | Update failed because something has happened to the content that the client didn't know about. |
| 500 Internal server error | Something really bad happened on the server. |
304 Not modified / if-none-match
When getting a content an ETag is provided with the response. If that ETag is used with an if-none-match header with the next request you will get a 304 Not modified response code.
Request:
$ curl --location \
--include \
--header "X-Auth-Token: $TOKEN" \
--header "If-None-Match: $ETAG" \
'http://ace-content-service:8081/content/alias/contentid/ZGU5YzViMzctNDM5My00'
Response:
HTTP/1.1 304 Not Modified
Date: Thu, 23 Nov 2017 07:40:16 GMT
Ace-Api-Version: 0.9.17
ETag: W/"c:MTY4M2ZlNDktMjNkYy00/1"
Error response body
The response body for an error contains a structured error message with a status code, an error message, and optional extra information related to the particular error that occurred. The following examples are for an update that failed because someone else had already updated the content.
{
"message": "Content was modified",
"statusCode": "40900",
"extraInfo": {
"conflictingVersion": "c:MTY4M2ZlNDktMjNkYy00:MTBmMTc5",
"committer": "admin",
"ETag": "W/\"c:MTY4M2ZlNDktMjNkYy00/3\"",
"lastModified": "1511423181361",
"revision": "c:YmNhYmZhMWQtZTk1Ni00/3"
}
}
Status codes
The status code is a five digit integer, where the first three digits correspond to an HTTP status code, and the last two digits may provide more detailed information.
The following is a non-exhaustive list of status codes that may occur:
| Error | Code | Explanation |
|---|---|---|
| VERSION_NOT_FOUND | 40403 | The content exists, but the particular version requested does not exist. |
| CONCURRENT_CONFLICT | 40901 | Update failed because content was updated by another process. extraInfo contains conflictingVersion, lastModified, revision, ETag and committer. |
| NOT_FOUND_CONFLICT | 40904 | Update failed because content no longer exists. |
Extra info
The extra info fields that the system supplies are listed in the following table. Note that custom callbacks can add custom fields not listed here.
| Field | Description |
|---|---|
| revision | The current revision on the server |
| conflictingVersion | The latest version created (may be the same as the client has if the conflict relates to something else) |
| committer | The username of the user that last modified the content |
| lastModified | The last time the content was modified, in milliseconds since the epoch |
| ETag | The ETag for the server's revision of the content, for use in a subsequent request |
Getting content in a variant
To require a custom variant, the variant query parameter must be supplied. The content must be made available in the given variant for this to work. See Config Content.
Request:
$ curl --location \
--include \
--header "X-Auth-Token: $TOKEN" \
'http://ace-content-service:8081/content/alias/contentid/ZGU5YzViMzctNDM5My00?variant=aceIndexing'
Writing content
Variants can't be used when updating content.
Getting content metadata
The Content Metadata endpoint can be used to list a content's unversioned Aspects.
To retrieve content metadata, issue a GET request to the normal content endpoint followed by /metadata. Please note that
metadata reads will return a redirect, so include the -L/--location option to curl:
$ curl --location \
--header "X-Auth-Token: $TOKEN" \
'http://ace-content-service:8081/content/alias/contentid/YmQyYzI4OGEtYjRhNC00/metadata'
Response:
{
"system": {
"id": "contentid/YmQyYzI4OGEtYjRhNC00",
"version": "c:NzAwZDFhNDYtOWU4ZS00:ODMzMzdm",
"modificationTime": "2020-02-28T07:50:29.598Z",
"creationTime": "2020-02-28T07:50:29.598Z",
"contentType": "_contentInfo"
},
"aspects": {
"_type": "_contentInfo",
"aceWorkflowState": {
"_type": "aceWorkflowState",
"workflows": []
},
"aceContentState": {
"_type": "aceContentState",
"hidden": false
},
"aceAliases": {
"_type": "aceAliases",
"aliases": {
"_type": "MAP::LIST::string",
"contentid": [
"YmQyYzI4OGEtYjRhNC00"
]
}
},
"aceViewInfo": {
"_type": "aceViewInfo",
"views": {
"_type": "MAP::aceViewInfoEntry",
"acePublic": {
"_type": "aceViewInfoEntry",
"history": [
{
"_type": "aceViewEvent",
"userId": "admin",
"version": "c:Y2E2Mjk1MmQtODllZS00:YjYwZTli",
"revision": 2,
"timestamp": "2020-03-05T12:50:14.406Z"
}
]
}
}
}
},
"status": {
"message": "OK",
"statusCode": "20000",
"extraInfo": {}
}
}
NOTE: content info aspects such as aceAliases, and aceViewInfo are not actually stored in
content but calculated when content info is read.
Getting content history/versions
The Content History endpoint can be used to retrieve a list of content versions.
To retrieve content history, issue a GET request to the normal content endpoint followed by /history. Please note that
history reads will return a redirect, so include the -L/--location option to curl:
$ curl --location \
--header "X-Auth-Token: $TOKEN" \
'http://ace-content-service:8081/content/alias/contentid/YmQyYzI4OGEtYjRhNC00/history'
Response:
{
"versions": [
{
"version": "c:MTY4M2ZlNDktMjNkYy00:MTBmMTc5",
"revision": {
"contentId": "c:MTY4M2ZlNDktMjNkYy00",
"revisionNumber": 0
},
"creationTime": 1511357609987,
"creatorId": "admin",
"views": []
},
{
"version": "c:MTY4M2ZlNDktMjNkYy00:MTBmMTc5",
"revision": {
"contentId": "c:MTRhNzZjNjMtODM0Ni00",
"revisionNumber": 1
},
"creationTime": 1511362859070,
"creatorId": "admin",
"views": []
},
{
"version": "c:MTY4M2ZlNDktMjNkYy00:MTBmMTc5",
"revision": {
"contentId": "c:OWQzODQwOTktOTljMC00",
"revisionNumber": 2
},
"creationTime": 1511422975819,
"creatorId": "admin",
"views": []
},
{
"version": "c:MTY4M2ZlNDktMjNkYy00:MTBmMTc5",
"revision": {
"contentId": "c:NGVjZDQwOTYtMzRhMy00",
"revisionNumber": 3
},
"creationTime": 1511423181360,
"creatorId": "admin",
"views": [
"aceLatest"
]
}
]
}
For every entry in the versions list of the response, the following information will be given:
- version: The Id of the version.
- revision: The first revision of the content where this version appeared.
- creationTime: The time when the version was created, in unix timestamp format.
- creatorId: The principal ID of the creator (can be a user or automated system) of the version.
- views: The views where the version is present. See Views Documentation for more information on views.
Operations
In addition to aspects, a write operation may include a list of additional ContentOperations. Operations are submitted as a list of operation objects.
{
"operations": [
{
"_type": "aceAssignToViews",
"views": ["acePublic"]
}
],
"system": {
"contentType": "doc_example_content"
},
"aspects": {
"doc_example": {
"_type": "doc_example"
}
}
}
Set Alias
The set alias operation assigns one alias to the content. Multiple instances of this operation can be included to assign multiple aliases.
| Field | Type | Description |
|---|---|---|
| _type | aceSetAlias | The operation type |
| namespace | string | The namespace for the alias to assign |
| alias | string | The alias to assign |
Example
Assigns the alias "foo/example.TourismArticle" to the content
{
"_type": "aceSetAlias",
"namespace": "foo",
"alias": "example.TourismArticle"
}
Assign to views
The assign to views operation assigns the version that is created to a number of views.
| Field | Type | Description |
|---|---|---|
| _type | aceAssignToViews | The operation type |
| views | array | The names of the views to assign this version of the content to |
Example
Assigns the new version to "myView" and "acePublic".
{
"_type" : "aceAssignToViews",
"views" : [
"myView",
"acePublic"
]
}
Assign to symbolic views
The assign to symbolic views symbolically assigns a number of views to one target view. The target view is not affected by this operation.
| Field | Type | Description |
|---|---|---|
| _type | aceAssignToSymbolicViews | The operation type |
| views | array | The names of the views to symbolically assign the target view to |
| targetView | string | The view that the assigned views should resolve to, prefixed with "@" |
Example
Makes "myView" and "siteView" resolve to whatever "acePublic" resolves to.
{
"_type" : "aceAssignToSymbolicViews",
"targetView": "acePublic",
"views" : [
"myView",
"siteView"
]
}
Content Metadata
This operation updates the content metadata aspects (i.e. unversioned metadata). Aspects are represented just like regular content aspects.
| Field | Type | Description |
|---|---|---|
| _type | aceContentMetadata | The operation type |
| aspects | object | An object containing the info aspects to update |
Example
Sets the time state and the security contexts for the content.
{
"system": {
"contentType": "doc_example_content"
},
"operations": [
{
"_type": "aceContentMetadata",
"aspects": {
"aceTimeState": {
"_type": "aceTimeState",
"views": {
"acePublic": {
"onTime": "2017-11-23T14:37:04Z"
}
}
},
"aceSecurityContext": {
"_type": "aceSecurityContext",
"owners": [
"aContext"
]
}
}
}
]
}
Handling files
Files are stored in the File Storage Server. See files WS documentation.
Authorization
The Web Service API checks authorization when getting, updating and creating content. (See the Permissions documentation for details about the permission system.)
There is a REST endpoint for retrieveing a user's Authorization Information. (WebService Endpoint is located in the Content Service, but this might change in the future.)
N.b. Right now, it is not possible to fetch the Authorization Information for other users.
Authorization Information Request
Example:
$ curl --location \
--header "X-Auth-Token: $TOKEN" \
'http://ace-content-service:8081/security/permission/kalle'
Response:
{
"contexts": {
"kalles_context_1": [
"editor"
],
"kalles_context_2": [
"editor"
],
"c2": [
"r2",
"r3"
]
},
"roles": {
"r2": {
"image": [
"Read",
"Write"
],
"article": [
"Read",
"Write",
"AssignToView",
"randomCustomPermission"
]
},
"editor": {
"com.atex.ace.content.AspectBeanContent": [
"Create",
"Read",
"Update",
"Delete"
]
},
"r3": {
"image": [
"Read",
"Write"
],
"article": [
"Read",
"Write",
"AssignToView",
"randomCustomPermission"
]
}
}
}
Conflict Handling
The Content API REST service uses an optimistic locking scheme based on the ETag and If-Match HTTP headers ([HTTP 1.1|http://www.w3.org/Protocols/rfc2616/rfc2616.html]). The idea is that when a content is fetched from the Content API with a simple GET the response will contain an ETag header.
When the client wants to update a content, the PUT request must include an If-Match header containing the ETag value for that content. If the If-Match header value does not match the ETag for the current version of the content, the operation is aborted and the Content API responds with a 409 Conflict HTTP response code, and a status code of 40900 in the error response.
When creating new content, the request must not contain an If-Match header. If a create operation is executed with an If-Match header the server responds with 412 Precondition failed HTTP response code and a status code of 41200 in the error response.
For clients that do not care about other clients changes the request parameter unsafeUpdate=true can be added and the If-Match header skipped, this will always overwrite changes.
Using the unsafeUpdate=true parameter might cause data loss when more than one client writes to the same content.
| Content operation | Method | Header |
|---|---|---|
| Get | GET | returns ETag |
| Create | POST | returns ETag |
| Update | PUT | require If-Match if not unsafeUpdate=true and returns new Etag |
Views
Clients of the Content API REST services don't explicitly perform any view version resolution, but instead automatically gets redirected to the relevant content revision service endpoint. Accessing content on a specific view is simply performed using a slightly different URL compared to normally:
$ curl --location \
--header "Accept: application/json" \
--header "X-Auth-Token: $TOKEN" \
'http://ace-content-service:8081/content/view/acePublic/alias/contentid/YmQyYzI4OGEtYjRhNC00'
This will redirect to the view revision of the content that exists on the view 'acePublic', if the content has a version on this view.
Response:
{
"system": {
"id": "contentid/YmQyYzI4OGEtYjRhNC00",
"version": "c:MTY4M2ZlNDktMjNkYy00:MTBmMTc5",
"modificationTime": "2017-11-23T15:35:37.225Z",
"creationTime": "2017-11-23T15:35:37.225Z",
"contentType": "doc_example_content"
},
"aspects": {
"_type": "doc_example_content",
"doc_example": {
"_type": "doc_example",
"title": "Hello, world!"
}
},
"status": {
"message": "OK",
"statusCode": "20000",
"extraInfo": {}
}
}
Views Service
View version assignment
For a content version to be available on a view, it has to be assigned to it first. This operation is available in the Content API REST services through the views service. You perform the operation by issuing an HTTP PUT request with a payload containing the content version to put on the view. Example:
$ curl --include \
--request PUT \
--header "If-Match: $ETAG" \
--data '{"version":"c:MTY4M2ZlNDktMjNkYy00:MTBmMTc5"}' \
--header "Content-Type: application/json" \
--header "X-Auth-Token: $TOKEN" \
'http://ace-content-service:8081/view/myView'
Response:
HTTP/1.1 200 OK
Date: Thu, 23 Nov 2017 15:52:42 GMT
Ace-Api-Version: 0.9.17
ETag: W/"c:MTY4M2ZlNDktMjNkYy00/1"
Content-Length: 0
After having performed the above operation, the content version c:MTY4M2ZlNDktMjNkYy00:MTBmMTc5 will be available on the myView view.
Request:
$ curl --header "X-Auth-Token: $TOKEN" \
'http://ace-content-service:8081/content/view/myView/alias/contentid/YmQyYzI4OGEtYjRhNC00'
Response:
HTTP/1.1 303 See Other
Date: Thu, 23 Nov 2017 16:08:16 GMT
Ace-Api-Version: 0.9.17
Location: http://ace-content-service:8081/content/view/myView/alias/contentid/YmQyYzI4OGEtYjRhNC00/0
Cache-Control: no-transform, must-revalidate, max-age=0
Content-Type: application/json;charset=utf-8
ETag: W/"c:MTY4M2ZlNDktMjNkYy00/1"
Content-Length: 169
{
"statusCode": 30300,
"message": "Symbolic version resolved",
"location": "/content/view/myView/alias/contentid/YmQyYzI4OGEtYjRhNC00/0"
}
It is also possible to a assign a new version of a content to one or more views using the AssignToViews operation on either an update or create of a content, see Operations for more information.
View content removal
For various reasons, sometimes content has to be taken off a view completely. This operation is available in the Content API REST services through the views service. You perform the operation by issuing an HTTP DELETE request.
Example:
$ curl --request DELETE \
--header "X-Auth-Token: $TOKEN" \
'http://ace-content-service:8081/view/myView/alias/contentid/YmQyYzI4OGEtYjRhNC00'
Note that the above request is with a content alias. After having performed the above operation, no version of the content contentid/YmQyYzI4OGEtYjRhNC00 will be available on the myView view.
In the payload, you can instead of a version supply a SymbolicViewAssignment, to link the view to another view within a content. The target view is prefixed with '@'.
{
"symbolic" : {
"alias" : "contentid/YmQyYzI4OGEtYjRhNC00",
"targetView" : "@acePublic"
}
}
$ curl --request PUT \
--data '{ "symbolic": { "alias": "contentid/YmQyYzI4OGEtYjRhNC00", "targetView": "@acePublic" }}' \
--header "Content-Type: application/json" \
--header "X-Auth-Token: $TOKEN" \
'http://ace-content-service:8081/view/myView'
Status in content result
The response to a content create or update now includes a status field which has the same format as an error response.
Partial success
ACE has status codes for partial create (20107). It is used when the content was created but some operation (in practice assigning an alias) failed after the create was finished. If a partial success is indicated, the failing operations will be included in subResults field of the status, as a list of objects containing the failed operation and the operation's status.
{
"status" : {
"extraInfo" : {},
"message" : "PARTIAL_CREATED",
"subResults" : [
{
"operation" : {
"namespace" : "test",
"alias" : "theBestTestAlias",
"_type" : "aceSetAlias"
},
"status" : {
"message" : "ALIAS_EXISTS",
"extraInfo" : {
"alias" : "contentid/YmQyYzI4OGEtYjRhNC00",
"alias" : "test/theBestTestAlias"
},
"statusCode" : "40910"
}
}
],
"statusCode" : "20107"
},
...
}
Bypassing the cache
Sometimes a client knows that it needs a certain revision of a content
(e.g. because it created it), but the content API may still have an
older version in cache. It is possible to request that the response be
based on that revision or a newer one, by including the query
parameter atLeastRevision in requests for unversioned (getting content with alias)
content or content history.
Request:
$ curl --location \
--header "X-Auth-Token: $TOKEN" \
'http://ace-content-service:8081/content/alias/contentid/c65015a0-4987-41f0-98b2-97e07d579dc0?atLeastRevision=0'
Response:
{
"system": {
"id": "contentid/YTRiNDQ1MjAtMGJlYS00",
"version": "c:MTY4M2ZlNDktMjNkYy00:MTBmMTc5",
"modificationTime": "2017-11-23T16:13:11.266Z",
"creationTime": "2017-11-23T16:13:11.266Z",
"contentType": "doc_example_content"
},
"aspects": {
"_type": "doc_example_content",
"doc_example": {
"_type": "doc_example",
"title": "Hello, world!"
}
},
"status": {
"message": "OK",
"statusCode": "20000",
"extraInfo": {}
}
}
Query Service
The query service can be used to query the content repository for specific types of content.
NOTE: the query service is not supported for Couchbase storage.
Content type
The content type query can be used to retrieve a response containing all content of a specific content type.
Example
The following request would return a list of all content of content type doc_example_content:
$ curl --header "Content-Type: application/json" \
--header "X-Auth-Token: $TOKEN" \
'http://ace-content-service:8081/query/contentType/doc_example_content'
Response:
[
{
"system": {
"id": "contentid/YTRiNDQ1MjAtMGJlYS00",
"version": "c:MTY4M2ZlNDktMjNkYy00:MTBmMTc5",
"modificationTime": "2017-11-23T16:13:11.266Z",
"creationTime": "2017-11-23T16:13:11.266Z",
"contentType": "doc_example_content"
},
"aspects": {
"_type": "doc_example_content",
"doc_example": {
"_type": "doc_example",
"title": "Hello, world!"
}
},
"status": {
"message": "OK",
"statusCode": "20000",
"extraInfo": {}
}
}
]