Skip to content

REST API

Derek Clemenzi edited this page May 22, 2020 · 131 revisions

All of these endpoints are hosted behind the server bean, which defaults to the following path:

/cxf/data

By default, the API directs all queries to the primary persistor for each operation in question. However, the Coalesce blueprints may be configured to allow secondary persistors to be addressed directly. If this is the case, a secondary persistor may be addressed by substituting an appropriate fragment for "data" in the endpoint: e.g., "cxf/elastic" for an Elasticsearch persistor.

Create operations always require a POST, while update operations always require a PUT. A PUT is used even when an update operation updates multiple objects, and therefore doesn't include an object key in the endpoint.

Where a response format (JSON or XML) is supplied as part of the endpoint, it must be supplied in lowercase: "/json" or "/xml".

An important note: for retrieving data, the search endpoint is much more efficient (that is, faster) than using read (GET) operations on the endpoints of specific data types--except in cases where the entire entity in its XML form is required--and is the preferred method. This applies even for addressing records by their keys.

Search

Endpoint

/search?_wadl
/search/complex

All requests for a search can be made to this endpoint (the "simple" search endpoint is deprecated), as POST operations. A search query forms the data block of a search request, and must include a search filter object ("group"), a "propertyNames" object (for the fields to be returned), and a "pageSize"; a "pageNumber" and a "sortBy" object are optional--see the Search Query Data Format below for details. A query can also include a "type", which should be name of the entity template that defines the type of entity being searched for (that is, the "name" field in the default "CoalesceEntity" recordset)--but this key is not required when the type of entity can be inferred from the recordset specified in the search criteria (see below).

It is not possible to perform searches that include filters for multiple recordsets, unless the underlying persistor supports joins. This limitation makes it impossible to search for multiple types (templates) of entities in a single search (again, unless joins are supported). The one exception is filters that include fields of the default "CoalesceEntity" recordset, which may be combined with filters based on any other recordset.

The search filter object consists of one or more sets of "criteria", each with a target field, search operator ("EqualTo", "Like", "Between", etc.), and search value or values. To negate the search operator in a given criteria set (and retrieve results that do not match the search criteria), add the attribute "not" with a value of true. Criteria sets are combined into "groups" joined by group operators ("AND", "OR"); search groups may be nested.

Numerical and boolean values can be entered as either the appropriate type or as strings; this applies to all fields in the request object. However, multiple search values (for example, as required by the "Between" operator) should be entered as a JSON array (they may also be submitted as a single string, with space-separated values, but this input format is deprecated)--and note that, in the case of multiple values, the correct key is "values" rather than "value".

Dates are entered as strings, in one of two accepted formats: "Sun Jan 01 00:00:00 GMT 1989" and "1989-01-01T00:00:00.000Z" (the decimal seconds are optional in the latter format). The first format is the format used by Coalesce in responses to search queries; for both formats, at present "GMT" and "Z" are the only accepted time zone codes. Date-range operators ("After", "Before", "During") may or may not exclude the supplied datetime, depending on the underlying persistor. At present, the "EqualTo" operator works for the second format, but not the first.

For basic entity fields (that is, the default fields of CoalesceEntity objects, such as "name" and "dateCreated", as opposed to the fields within recordsets), use "coalesceEntity" as the recordset name. (Note, though, that the default Derby persistor may not accept the prefixed "coalesceEntity"--in this case, use the field name by itself.) The linkage table can also be searched, by using "CoalesceLinkange" as the recordset name. Searching the linkage table actually provides a method of finding all the links originating from a given entity (field name "entity1Key") that's more efficient than using the linkage API to do the same. In addition, it's possible to search the linkage table for target entities (field name "entity2key") with equal efficiency (making bi-directional links arguably superfluous).

The default value of "matchCase" is true, but some persistors and fields do not respect the value of "matchCase", and searches on these persistors/fields may be either case-sensitive or case-insensitive. (At some point in the future, documentation will be provided for these differing capabilities.) Note that "matchCase" applies only to the search value(s). Search operators and sort order must always be written in upper camelcase, while group operators are case-insensitive. Recordset and field/property names are passed through to the underlying persistor(s) without parsing; for most persistors, these values will be case-insensitive.

Method Action Status Code Format
POST Sends a search query to the server 200 JSON

Search Query Data Format

{
    "pageSize": 200,
    "pageNumber": 1,
    "sortBy": [
        {
            "propertyName": "documentdb.documentdate", 
            "sortOrder": "ASC"
        {,
        {
            "propertyName": "documentdb.documentlength",
            "sortOrder": "DESC"
        }
    ],
    "propertyNames": [
        "CoalesceEntity.name"
    ],
    "group":{
        "operator": "AND",
        "criteria":[
            {
                "recordset": "coalesceentity",
                "field": "name",
                "operator": "EqualTo",
                "value": "article",
                "matchCase": false
            }
        ],
        "groups": [
            {
                "operator": "AND", 
                "criteria": [
                    {
                        "recordset": "documentdb",
                        "field": "documenttitle",
                        "operator": "EqualTo",
                        "value": "great expectations",
                        "matchCase": false,
                        "not": true
                    },
                    {
                        "recordset": "documentdb",
                        "field": "pagecount",
                        "operator": "Between",
                        "values": [100, 200],
                        "matchCase": false
                    },
                    {
                        "recordset": "documentdb",
                        "field": "publicationlocation",
                        "operator": "BBOX",
                        "value": "POLYGON((10 10, 10 20, 20 10, 20 20))",
                        "matchCase": false
                    }
                ]
            }
        ]
    }
}

Search Group Operators

Operator Function
AND Finds values that match all of multiple queries
OR Finds values that match any of multiple queries

Search Criteria Operators

Operator Function Number of Values
EqualTo Finds an identical value 1
GreaterThan Checks if search value is greater than field value 1
GreaterThanOrEqualTo Checks if search value is greater or equal to field value 1
LessThan Checks if search value is less than field value 1
LessThanOrEqualTo Checks if search value is less or equal to field value 1
NotEqualTo Finds field values not equal to the search value 1
Like Finds field values similar to the search value 1
Between Checks for field values in the range between two space-separated search values 2
During Checks for field values between two space-separated date-time values 2
After The behavior of this operator depends on the persistor. It may check for a field value after the specified date-time value, or it may check for a field value at the same time as or after the specified date-time value 1
Before Checks for a field value before the specified date-time value 1
BBOX Checks for a field value within the bounding box defined by a WKT geometric object. Note that, regardless of the type or complexity of this geometric object, Coalesce projects it onto a rectangular bounding box oriented on the lat/long grid 1
NullCheck Checks for null field values 0

These operators are a subset of the most commonly used OGC search operators. Some operators may not work with some persistors and/or field types.

Entity Data Controller

Endpoints

/entity[/<format>]

For a create (POST) operation, the data block should consist of a JSON or XML representation of the entity in question. Including a UUID key as part of the entity is optional, and if none is included, the server generates one randomly; in either case, the server returns the new entity's key as the content of the response. Likewsie, the server will replace a missing or null "dateCreated" field with the current time, and it will overwrite any value provided in the "lastModified" field, again using the current time. If a partial entity is uploaded (for example, an entity with records missing some fields, or with a recordset missing some records), the server will fill in empty attributes with default or null values.

Method Action Status Code Formats Default Format
POST Creates a new entity 200 xml, json JSON
DELETE Marks the entities as deleted 204 json JSON
/entity/<key>[/<format>]

For an update (PUT) operation, the data block should consist of a JSON or XML representation of the entity in question. This representation must include not only the updated field(s), but all sections, recordset, records, and fields in the original, and all of the original's UUID keys (not only the entity's key, but all section, recordset, record, and field keys). Failure to match keys will result in the creation of duplicate records within the modified entity.

Note that retrieving an entity via the entity API is not as efficient as using the search API--unless retrieving the entire entity, with all its fields, in XML form, is required.

Method Action Status Code Formats Default Format
GET Retrieves an entity in the specified format. 200 xml, json JSON
PUT Updates an existing entity 204 xml, json JSON
DELETE Marks an entity as deleted 204

Configuration

<bean class="com.incadencecorp.coalesce.services.crud.service.data.jaxrs.EntityDataControllerJaxRS">
    <argument>
        <bean class="com.incadencecorp.coalesce.services.crud.service.client.CrudFrameworkClientImpl">
            <argument ref="framework" />
        </bean>
    </argument>
    <argument ref="persister" />
</bean>

Template Data Controller

Endpoints

/templates[/<format>]

In a create operation (POST), the server generates the template key as a hash of the template's name, source, and version attributes, and therefore, no key should be included in the entity.

Method Action Status Code Formats Default Format
POST Creates a new entity template 200 xml, json JSON
GET Retrieves a list of saved templates 200 json JSON
/templates/<key>[/<format>]

Reading a template (GET) produces slightly different results between XML and JSON forms: the server returns no "dateCreated" field for XML templates, but it creates JSON templates at bootup from their XML counterparts, which results in the insertion of an essentially arbitrary date in this field (a quirk that's generally harmless unless this arbitrary value is mistaken for a default).

For an update (PUT), the template representation must include the entity UUID key, which must match the key in the endpoint (this is a quality check, to help prevent accidental updates to the wrong templates). Updating a template--rather than creating a new template, with a different version number--may have unpredictable consequences, depending on the persistor and its settings (especially caching settings). If a template update is unavoidable, a server/container restart or other measures may be necessary (for example, in Elasticsearch, it may be necessary to delete the index in question).

For some persistors (e.g., the default Apache Derby), deleting templates is not implemented, and attempting to delete a template will produce a status code of 500 ("Server Error").

Method Action Status Code Formats Default Format
GET Retrieves an entity template 200 xml, json JSON
PUT Updates an existing entity template 204 xml, json JSON
DELETE Marks an entity template as deleted 204 xml, json JSON
/templates/<key>/register
Method Action Status Code
PUT Registers an entity template that has already been created 204
/templates/<name>/<source>/<version>[/<format>]
Method Action Status Code Formats Default Format
GET Retrieves an entity template 200 xml, json JSON
/templates/<key>/recordsets
Method Action Status Code Format
GET Returns the template's recordsets 200 JSON
/templates/<key>/recordsets/<recordset key>/fields
Method Action Status Code Format
GET Returns the recordset's fields 200 JSON

Configuration

<bean class="com.incadencecorp.coalesce.services.search.service.data.jaxrs.TemplateDataControllerJaxRS">
    <argument>
        <bean class="com.incadencecorp.coalesce.framework.CoalesceFramework">
            <property name="authoritativePersistor" ref="persister" />
        </bean>
    </argument>
</bean>

Linkage Data Controller

Endpoints

/linkage
Method Action Status Code Format
PUT Sets multiple linkages 204 JSON
DELETE marks multiple linkages for deletion 204 JSON
/linkage/<key>
Method Action Status Code Format
GET Gets all linkages for an entity 200 JSON

The first endpoint makes it possible to submit linkages in bulk jobs, and also allows the submission of bi-directional links (which Coalesce instantiates by creating links in each of the corresponding entities). Both of the endpoints use a special format based on the Coalesce GraphLink class, which includes only a subset of the attributes in the linkage data model, with somewhat different names; "source", "target", and "type" are mandatory attributes, "label" and "biDirectional" are optional, and "status" is set by the server (but can also be changed through the API).

The PUT and DELETE methods accept an array of these linkages (which need not all have the same source entity), and the GET method returns a similar array. If "biDirectional" is true, the server creates or deletes a reciprocal link (a bidirectional "IsChildOf" is reciprocated by an "IsParentOf", etc.). Since the server creates two separate (unidirectional) links to instantiate a bidirectional link, there's no such thing as a bidirectional link stored within a Coalesce persistor, and therefore "biDirectional" is not included in links returned by the GET method.

Note that retrieving an entity's linkages via the linkage API is not as efficient as using the search API (with "CoalesceLinkage" as the recordset name and "entity1Key" as the search field); in addition, using the search API allows retrieval of unidirectional linkages by target (using "entity2Key").

Linkage Array Format

[
    {
         "source": <entity1 key>,
         "target": <entity2 key>,
         "label": "IsChildOf",
         "type": "IS_CHILD_OF",
         "biDirectional": false,
         "status": "ACTIVE"
    },
    {
         "source": <entity3 key>,
         "target": <entity4 key>,
         "label": null,
         "type": "UNDEFINED",
         "biDirectional": true,
         "status": "ACTIVE"
    }
]

Linkage Types

Type
UNDEFINED
IS_CHILD_OF
IS_PARENT_OF
CREATED
WAS_CREATED_BY
HAS_MEMBER
IS_A_MEMBER_OF
HAS_PARTICIPANT
IS_A_PARTICIPANT_OF
IS_WATCHING
IS_BEING_WATCHED_BY
IS_A_PEER_OF
IS_OWNED_BY
HAS_OWNERSHIP_OF
IS_USED_BY
HAS_USE_OF
SUCCESSOR
PREDECESSOR
CROSS_DOMAIN_SOURCE
CROSS_DOMAIN_TARGET
IS_INPUT_PARAMETER_TO
HAS_INPUT_PARAMETER_OF
IS_INPUT_TO
HAS_INPUT_OF
IS_OUTPUT_TO
HAS_OUTPUT_OF
IS_PRODUCT_OF
HAS_PRODUCT

Property Data Controller

Endpoints

/property
Method Action Status Code Format
GET Gets all properties as key / value pairs 200 JSON
POST Gets properties as key / value pairs of specified properties (passed in as an array) 200 JSON
PUT Updates the values of multiple properties 204 JSON
/property/<property name>
Method Action Status Code Format
GET Gets the property's value 200 Text
PUT Updates the property's value 204 Text
/property/<filename>.json

This endpoint operates on an entire properties file, rather than a single property, or a list of them.

Method Action Status Code Format
GET Gets the JSON document 200 JSON
PUT Saves the JSON document 204 JSON

Configuration

By default client side properties are stored in config/client.properties and you don't need to specify any properties when defining the bean. The following shows how you can override this behavior. You can switch the connector to any connector to pull settings from memory or any other implementation.

<bean class="com.incadencecorp.coalesce.services.common.jaxrs.PropertyControllerJaxRS">
    <property name="key" value="client.properties" />
    <property name="connector">
        <bean class="com.incadencecorp.unity.common.connectors.FilePropertyConnector" >
            <argument value="config" />
        </bean>
    </property>
</bean>