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="..."
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/9034880f-920a-4d0c-a3cc-91ae6664ecc7",
    "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": "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/9034880f-920a-4d0c-a3cc-91ae6664ecc7'

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/9034880f-920a-4d0c-a3cc-91ae6664ecc7",
    "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/9034880f-920a-4d0c-a3cc-91ae6664ecc7",
    "version": "c:b3b65750-f1fd-49ce-b323-61028605a623:3878d5a0-b4e1-4a5b-82d7-721fca7a5f91",
    "modificationTime": "2017-11-22T13:33:29.990Z",
    "creationTime": "2017-11-22T13:33:29.990Z",
    "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/9034880f-920a-4d0c-a3cc-91ae6664ecc7'

HTTP response

{
  "system": {
    "id": "contentid/9034880f-920a-4d0c-a3cc-91ae6664ecc7",
    "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/9034880f-920a-4d0c-a3cc-91ae6664ecc7'

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/66da43dc-3361-4a52-a3dd-3ea0cd80905b",
     "version": "draft:9a027596-7f0e-49be-b5b5-060e64e23a3b: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/9034880f-920a-4d0c-a3cc-91ae6664ecc7",
    "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/9034880f-920a-4d0c-a3cc-91ae6664ecc7'

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/9034880f-920a-4d0c-a3cc-91ae6664ecc7?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.

Request:

$ curl --header "X-Auth-Token: $TOKEN" \
       'http://ace-content-service:8081/content/alias/contentid/9034880f-920a-4d0c-a3cc-91ae6664ecc7/info'

Response:

{
  "system": {
    "id": "contentid/9034880f-920a-4d0c-a3cc-91ae6664ecc7",
    "version": "c:MTY4M2ZlNDktMjNkYy00:MTBmMTc5",
    "modificationTime": "2017-11-22T13:33:29.990Z",
    "creationTime": "2017-11-22T13:33:29.990Z",
    "contentType": "_contentInfo"
  },
  "aspects": {
    "_type": "_contentInfo",
    "aceAliases": {
      "_type": "aceAliases",
      "aliases": {
        "_type": "MAP::LIST::string",
        "contentid": [
          "9034880f-920a-4d0c-a3cc-91ae6664ecc7"
        ]
      }
    }
  },
  "status": {
    "message": "OK",
    "statusCode": "20000",
    "extraInfo": {}
  }
}

Getting content history/versions

The Content History endpoint can be used to retrieve a list of content versions.

Request:

$ curl --header "X-Auth-Token: $TOKEN" \
       'http://ace-content-service:8081/content/alias/contentid/9034880f-920a-4d0c-a3cc-91ae6664ecc7/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 version 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/0413d6bf-3283-474e-8c96-f378ff0b7337'

This will redirect to the version of the content that exists on the view 'acePblic', if the content has a version on this view.

Response:

{
  "system": {
    "id": "contentid/894ff9b0-cd47-4916-97ac-327a20ccbf1b",
    "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/myViewalias/alias/contentid/894ff9b0-cd47-4916-97ac-327a20ccbf1b'

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/version/c:MTY4M2ZlNDktMjNkYy00:MTBmMTc5
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/version/c:MTY4M2ZlNDktMjNkYy00:MTBmMTc5"
}

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/0413d6bf-3283-474e-8c96-f378ff0b7337'

Note that the above request is with a content alias. After having performed the above operation, no version of the content contentid/0413d6bf-3283-474e-8c96-f378ff0b7337 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/0413d6bf-3283-474e-8c96-f378ff0b7337",
      "targetView" : "@acePublic"
   }
}
$ curl --request PUT \
       --data '{ "symbolic": { "alias": "contentid/0413d6bf-3283-474e-8c96-f378ff0b7337", "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" : "0344e252-25a7-46ca-8343-a476fb941fcf",
               "_type" : "aceSetAlias"
            },
            "status" : {
               "message" : "ALIAS_EXISTS",
               "extraInfo" : {
                  "alias" : "contentid/99efe974-89d9-4fa0-af0a-647d5b1392cd",
                  "alias" : "test/0344e252-25a7-46ca-8343-a476fb941fcf"
               },
               "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/c65015a0-4987-41f0-98b2-97e07d579dc0",
    "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": {}
  }
}