-
Notifications
You must be signed in to change notification settings - Fork 4
RESTful Endpoints
All active RESTful endpoints can be found in ./server/routes.js
.
This page gives documentation and examples to each endpoint.
All the endpoints share the same error handling. When error(s) happens, error(s) will be returned in following JSON format(just an example):
[
{ "msgCat": "GENERAL", "msgName": "GENERAL_ERROR", "msgType": "E",
"msgShortText": "Error happened", "msgLongText": "Error happened", "showLongText": false }
]
The input JSON should be a correct representation of an given entity, which means:
- It must have a valid 'ENTITY_ID';
- No 'INSTANCE_GUID' is given, as it will be given by JOR and returned when successfully created;
- All mandatory Relations(with cardinality equals '[1..1]' or '[1..n]') are given;
- If Relationship is given, the partner instance should be valid;
- A lot of other checks, like foreign key, relation validity, relationship validity, primary key missing, and so on.
If any error happened, the instance will not be saved in DB, and error messages will be returned. Otherwise, the return is the JSON of the instance with INSTANCE_GUID.
Example:
POST http://localhost:3000/api/entity
Accept: */*
Cache-Control: no-cache
Content-Type: application/json
{ "ENTITY_ID": "person",
"person": {"HEIGHT": "180", "GENDER": "male", "HOBBY":"Reading, Movie, Coding", "TYPE": "employee", "SYSTEM_ACCESS": "portal"},
"r_user": {"USER_ID": "DH999", "USER_NAME":"John", "DISPLAY_NAME": "John Wu"},
"r_email": [{"EMAIL": "dh999@hotmail.com", "TYPE": "private", "PRIMARY":1}],
"r_employee": {"USER_ID": "DH999", "COMPANY_ID":"Darkhouse", "DEPARTMENT_ID":"Development","TITLE":"Developer"},
"relationships":[
{ "RELATIONSHIP_ID": "rs_user_role",
"values":[
{ "SYNCED":0,
"PARTNER_INSTANCES":[
{"ENTITY_ID":"system_role", "ROLE_ID":"system_role", "INSTANCE_GUID":"5F50DE92743683E1ED7F964E5B9F6167"}]}
]
}]
}
The given JSON contains the attributes that are required for change, as well as those primary key attributes which are used for identifying a tuple. Both ENTITY_ID and INSTANCE_ID must be given. The reserved field "action" is introduced to each relation tuple. Its value could be one of the following: "update", "add", and "delete".
If any error happened, the change will not be saved in DB, and error messages will be returned. Otherwise, no error message means success.
The example below will do the following changes:
- Update the HEIGHT and HOBBY of "person" relation;
- Update the USER_NAME of "r_user" relation;
- Add a new email address;
- Add a new relationship to "system_role".
PUT http://localhost:3000/api/entity
Accept: */*
Cache-Control: no-cache
Content-Type: application/json
{ "ENTITY_ID": "person",
"INSTANCE_GUID": "2FBE7490E10F11E8A90957FA46F2CECA",
"person": {"action": "update", "HEIGHT": 180, "HOBBY":"Reading, Movie"},
"r_user": {"action": "update", "USER_ID": "DH999", "USER_NAME":"JohnWu"},
"r_email": [{"action": "add", "EMAIL": "dh999@darkhouse.com", "TYPE": "work", "PRIMARY":0}],
"relationships":[
{
"RELATIONSHIP_ID": "rs_user_role",
"values": [
{
"action": "add",
"VALID_FROM": "2020-12-31 00:00:00",
"VALID_TO": "2030-12-31 00:00:00",
"SYNCED": 1,
"PARTNER_INSTANCES": [
{
"ENTITY_ID": "system_role",
"ROLE_ID": "system_role",
"INSTANCE_GUID": "F914BC7E2BD65D42A0B17FBEAD8E1AF2"
}
]
}
]
}]
}
This endpoint is used to overwrite an instance as a whole with a given JSON. It requires both ENTITY_ID and INSTANCE_GUID, like changing an instance; however, it doesn't require "action" for each relation tuple, like creating an instance.
For those appeared relations in JSON, the value will replace the corresponding values in DB. For those not appeared relations, their value will be deleted in DB. This API is useful in some UI technologies which always overwrites an entity as a whole. The benefit is you don't have to trace every changed piece, just simply post the latest status of the instance to the backend store.
Besides it may introduce some performance overhead, another limitation is that relationships are not supported in the "overwrite" mode. This is because a relationship always deals with more than 2 instances, thus cannot be overwritten from single side.
If any error happened, the overwrite will not happen, and error messages will be returned. Otherwise, no error message means success.
Example:
PUT http://localhost:3000/api/entity/overwrite
Accept: */*
Cache-Control: no-cache
Content-Type: application/json
{ "ENTITY_ID": "person",
"INSTANCE_GUID": "2FBE7490E10F11E8A90957FA46F2CECA",
"person": {"HEIGHT": "180", "GENDER": "male", "HOBBY":"Reading, Movie, Coding, Singing"},
"r_user": {"USER_ID": "DH999", "USER_NAME":"JohnWu", "DISPLAY_NAME": "John Wu"},
"r_email": [{"EMAIL": "dh999@hotmail.com", "TYPE": "private", "PRIMARY":1}],
"r_employee": {"USER_ID": "DH999", "COMPANY_ID":"Darkhouse", "DEPARTMENT_ID":"Development","TITLE":"Developer"}
}
If successfully called, the return is a complete entity instance in JSON. Otherwise, error messages will be returned.
Example:
GET http://localhost:3000/api/entity/instance/2FBE7490E10F11E8A90957FA46F2CECA
Accept: */*
Cache-Control: no-cache
Use this endpoint, you can retrieve the selected Relations and Relationships through instance UUID. This endpoint well resolves the over-fetching and under-fetching issues. It can not only save performance, but also harden the security.
The following example requests 2 Relations: "r_user" and "r_email" from a person entity, together with one Relationship "rs_user_role". The return is a projection of the entity instance with attributes of "r_user", "r_email", and "rs_user_role" if successful.
POST http://localhost:3000/api/entity/instance/piece/2FBE7490E10F11E8A90957FA46F2CECA
Accept: */*
Cache-Control: no-cache
Content-Type: application/json
{
"RELATIONS": ["r_user", "r_email"],
"RELATIONSHIPS": ["rs_user_role"]
}
The second example is given to show the possibility of recursively retrieving partners' information through Relationships. If you also want some of the partners' information. You don't need to make 2 or more requests. You can request the partners' information in the Relationships using "PARTNER_ENTITY_PIECES".
Like below request, it will return the assigned system roles and the married person's information together with its own information. You can recursively request all the entities involved in a relationship network.
POST http://localhost:3000/api/entity/instance/piece/2FBE7490E10F11E8A90957FA46F2CECA
Accept: */*
Cache-Control: no-cache
Content-Type: application/json
{
"RELATIONS": ["r_user", "r_personalization"],
"RELATIONSHIPS": [
{"RELATIONSHIP_ID": "rs_user_role",
"PARTNER_ENTITY_PIECES": [
{"ENTITY_ID": "permission",
"piece": {"RELATIONS": ["r_role"], "RELATIONSHIPS": ["rs_user_role"]}}]},
{"RELATIONSHIP_ID": "rs_marriage",
"PARTNER_ENTITY_PIECES": [
{"ENTITY_ID": "person",
"piece": {"RELATIONS": ["person"]}}]}
]
}
Apart from INSTANCE GUID, we usually use business ID to identify an instance. For example, USER_ID is one of the business identification of a person entity, which belongs to the relation "r_employee". You need to make sure the business ID can uniquely identify the entity, otherwise, it will return the first hit that matches this ID. The return is a complete instance in JSON if successful.
Example:
POST http://localhost:3000/api/entity/instance
Accept: */*
Cache-Control: no-cache
Content-Type: application/json
{
"RELATION_ID": "r_employee",
"USER_ID": "DH001"
}
The endpoint behaves similar to Get pieces of an instance by UUID, except it uses business ID.
Example 1:
POST http://localhost:3000/api/entity/instance/piece
Accept: */*
Cache-Control: no-cache
Content-Type: application/json
{
"ID": {
"RELATION_ID": "r_user",
"USER_ID": "DH001"
},
"piece": {
"RELATIONS": ["r_user", "r_email"],
"RELATIONSHIPS": ["rs_user_role"]
}
}
Example 2, retrieve partner's information:
POST http://localhost:3000/api/entity/instance/piece
Accept: */*
Cache-Control: no-cache
Content-Type: application/json
{
"ID": {
"RELATION_ID": "r_user",
"USER_ID": "DH001"
},
"piece": {
"RELATIONS": ["r_user", "r_personalization"],
"RELATIONSHIPS": [
{"RELATIONSHIP_ID": "rs_user_role",
"PARTNER_ENTITY_PIECES": [
{"ENTITY_ID": "permission",
"piece": {"RELATIONS": ["r_role"], "RELATIONSHIPS": ["rs_user_role"]}}]},
{"RELATIONSHIP_ID": "rs_marriage",
"PARTNER_ENTITY_PIECES": [
{"ENTITY_ID": "person",
"piece": {"RELATIONS": ["person"]}}]}
]
}
}
If successfully called, the entity is marked as deleted in the table ENTITY_INSTANCES with field DEL set to true. Otherwise, error messages will be returned.
Example:
PUT http://localhost:3000/api/entity/instance/softDelete/308B94F011A911E9927AC30A42C011EC
Accept: */*
Cache-Control: no-cache
If successfully called, a soft-deleted entity is restored by setting value of DEL in table ENTITY_INSTANCES to false. Otherwise, error messages will be returned.
Example:
PUT http://localhost:3000/api/entity/instance/restore/308B94F011A911E9927AC30A42C011EC
Accept: */*
Cache-Control: no-cache
If successfully called, the instance will be deleted physically from DB. Otherwise, error messages will be returned.
Example:
DELETE http://localhost:3000/api/entity/instance/308B94F011A911E9927AC30A42C011EC
Accept: */*
Cache-Control: no-cache
You use this endpoint to combine multiple operations in one call. This is useful in some circumstances that multiple instances need to be processed in one transaction. For example, you want to create 2 people and marry them. You want this transaction to be finished in one call. And if failed, all the operations should be rolled back.
You achieve above requirement by composing below JSON. It combines 2 "createInstance", with the first one create the male person, and the second one create the female person. In the second one, the marriage relationship is also added. However, the partner's "INSTANCE_GUID" is empty, as at the time the JSON is composing, we don't know the INSTANCE_GUID of the male person.
The "replacements" is introduced to move value of the "movePath" to the "toPath". In this example, it finds the returned INSTANCE_GUID of the first person, and move the value to the partner's INSTANCE_GUID of the second person.
Both operations have set "noCommit" to true, which means the operation will not be committed to DB until all operations are finished.
POST http://localhost:3000/api/entity/orchestrate
Accept: */*
Cache-Control: no-cache
Content-Type: application/json
[
{
"action": "createInstance",
"noCommit": true,
"instance": {
"ENTITY_ID": "person",
"person": {"HEIGHT": 1.75, "GENDER": "Male", "FINGER_PRINT": "CA67DE15727C72961EB4B6B59B76743E", "HOBBY":"Game", "TYPE": "employee"},
"r_email": [{"EMAIL": "DH999@darkhouse.com.cn", "TYPE": "PRIVATE", "PRIMARY":1}],
"r_employee": {"USER_ID": "DH999", "COMPANY_ID":"DARKHOUSE", "DEPARTMENT_ID": "Development", "TITLE": "Developer", "GENDER":"Male"}
}
},
{
"action": "createInstance",
"noCommit": true,
"replacements": [{
"movePath": [0, "result", "instance", "INSTANCE_GUID"],
"toPath": ["relationships", 0, "values", 0, "PARTNER_INSTANCES", 0, "INSTANCE_GUID"]
}],
"instance": {
"ENTITY_ID": "person",
"person": {"HEIGHT": 1.65, "GENDER": "Female", "FINGER_PRINT": "CA67DE15727C72961EB4B6B59B76743F", "HOBBY":"Drama", "TYPE": "employee"},
"r_email": [{"EMAIL": "DH998@darkhouse.com.cn", "TYPE": "PRIVATE", "PRIMARY":1}],
"r_employee": {"USER_ID": "DH998", "COMPANY_ID":"DARKHOUSE", "DEPARTMENT_ID": "Development", "TITLE": "Tester", "GENDER":"Female"},
"relationships": [
{"RELATIONSHIP_ID": "rs_marriage",
"values":[{
"action": "add", "VALID_FROM":"", "VALID_TO":"2030-12-31 00:00:00", "REG_PLACE": "SH",
"PARTNER_INSTANCES":[{"ENTITY_ID":"person","ROLE_ID":"husband","INSTANCE_GUID": "", "NO_EXISTING_CHECK": true}]}]}]}
}
]
The return will be either error messages if any of the operation gets failed, or the updated operation list. Each operation in list will be updated with a "result" attribute. Depends on different operation, the result is also different.
Below gives supported orchestration operations. You can combine any number of the operations with any sequence. And they will be executed in the given sequence. Their definition and result are also illustrated.
const operation =
{
action: 'createInstance',
replacements: [], // Optional
noCommit: true, // If true, the changes will not committed to DB
instance: {} // the to-be-created instance in JSON
result: {updatedInstance, updateSQLs} // Return Object
}
const operation =
{
action: 'changeInstance',
replacements: [], // Optional
noCommit: true, // If true, the changes will not committed to DB
instance: {} // The changed instance in JSON
result: {updateSQLs} // Return Object
}
const operation =
{
action: 'softDeleteInstanceByGUID',
noCommit: true, // If true, the changes will not committed to DB
instance: {INSTANCE_GUID: ''} // To-be-deleted Instance GUID
result: {updateSQLs} // Return Object
}
const operation =
{
action: 'hardDeleteByGUID',
noCommit: true, // If true, the changes will not committed to DB
instance: {INSTANCE_GUID: ''} // To-be-deleted Instance GUID
result: {updateSQLs} // Return Object
}
const operation =
{
action: 'getInstancePieceByGUID',
noCommit: true, // If true, the changes will not committed to DB
instance: {INSTANCE_GUID: '', RELATIONS: [], RELATIONSHIPS: []} // Instance pieces
result: {instance} // Return Object
}
A query is defined as a JSON object with 2 mandatory attributes: "ENTITY_ID" and "RELATION_ID". You must tell the system on which entity and which leading relation the query is made on.
"PROJECTION" is an array in which you can include fields not only from the leading relation, but also from all the associated relations. The system helps you to do the sql-joins. If "PROJECTION" is not given, then it means all the fields from the leading relation will be projected.
The filter is limited with operators: EQ(Equal), NE(Not Equal), GT(Greater Than), GE(Greater than and Equal), LT(Less Than), LE(Less Than and Equal), and BT(Between). You can also use fields from the associated Relations to do the filtering and sorting.
You can also define sort criteria. On which which fields you want to sort the result sets, ascending(asc) or descending(desc). The return is a list of entries that fulfills the query.
The below example query data in Relation "r_user" of "person" entity. It projects attributes: "USER_ID", "USER_NAME", "GIVEN_NAME" in Relation "r_user". Attribute "COMPANY_ID" is project from Relation "r_employee", as association is already defined between "r_user" and "r_employee". It filters on attributes: "USER_ID" and "LANGUAGE" in Relation "r_personalization". It sorts on attribute: "LANGUAGE" in Relation "r_personalization".
POST http://localhost:3000/api/query
Accept: */*
Cache-Control: no-cache
Content-Type: application/json
{
"ENTITY_ID": "person",
"RELATION_ID": "r_user",
"PROJECTION": [
"USER_ID",
"USER_NAME",
"GIVEN_NAME",
{"FIELD_NAME": "COMPANY_ID", "ALIAS": "Company", "RELATION_ID": "r_employee"}
],
"FILTER": [
{
"FIELD_NAME": "USER_ID",
"OPERATOR": "BT",
"LOW": "DH001",
"HIGH": "DH999"
},
{
"FIELD_NAME": "LANGUAGE",
"OPERATOR": "EQ",
"RELATION_ID": "r_personalization",
"LOW": "ZH"
}
],
"SORT": [
{
"FIELD_NAME": "LANGUAGE",
"RELATION_ID": "r_personalization",
"ORDER": "desc"
}
]