Using nestedFields to Audit Entry History
Liferay 7.4 U72+/GA72+
When you enable entry history for an object definition, you can use the nestedFields
parameter with REST APIs to audit entry events. Add nestedFields=auditEvents
to the path for GET requests (e.g., http://localhost:8080/o/c/tickets/?nestedFields=auditEvents
).
To get started, set up a new Liferay 7.4 instance and prepare the provided tutorial code. Then, run the scripts to create entries, update them, and query those changes using the nestedFields
parameter.
Using REST APIs to view an entry’s history requires both the View
and Object Entry History
permissions for the entry. See Permissions Framework Integration.
Setting Up a Liferay Instance
Start a new Liferay instance by running
docker run -it -m 8g -p 8080:8080 liferay/portal:7.4.3.112-ga112
Sign in to Liferay at http://localhost:8080. Use the email address test@liferay.com and the password test. When prompted, change the password to learn.
Next, enable Liferay’s persistent audit message processor. Then create and publish an object definition.
Enabling the Persistent Audit Message Processor
-
Open the Global Menu () → Control Panel tab, → System Settings.
-
Under Security, click Audit and go to the Persistent Message Audit Message Processor tab.
-
Check Enabled.
-
Click Save.
Creating the Object Definition
-
Open the Global Menu (), go to the Control Panel tab, and click Objects.
-
Create an object draft.
Field Value Label Able
Plural Label Ables
Name Able
-
Add this field to the draft.
Label Field Name Type Required Name
name
Text ✔ -
In the Details tab, toggle Enable Entry History.
-
Publish the object.
Once published, you can access the object via Headless APIs.
Preparing the Sample Code
Download and unzip the sample code:
curl https://resources.learn.liferay.com/dxp/latest/en/building-applications/objects/understanding-object-integrations/using-custom-object-apis/liferay-g4m3.zip -O
unzip liferay-g4m3.zip
The sample code includes shell scripts for creating, updating, and querying object entries.
For a complete list of APIs generated for site and company objects, see Objects Headless Framework Integration. You can view and test custom object APIs via the Liferay API Explorer at [server]:[port]/o/api
(e.g., localhost:8080/o/api
). Click REST Applications and select an API.
Using the Sample Code
-
Navigate to the
curl
folder in theliferay-g4m3
project.cd liferay-g4m3/curl
-
Execute
Able_POST_ToCompany
to create threeAble
entries../Able_POST_ToCompany.sh
{ ... "externalReferenceCode" : "able-one", "id" : 47512, ... "name" : "Able 1 - Foo" } { ... "externalReferenceCode" : "able-two", "id" : 47514, ... "name" : "Able 2 - Foo" } { ... "externalReferenceCode" : "able-three", "id" : 47516, ... "name" : "Able 3 - Foo" }
-
Execute
Able_PATCH_ByExternalReferenceCode
with theable-one
ERC../Able_PATCH_ByExternalReferenceCode.sh able-one
This updates the entry’s name field twice.
{ ... "externalReferenceCode" : "able-one", "id" : 47512, ... "name" : "Able 1 - Bar" } { ... "externalReferenceCode" : "able-one", "id" : 47512, ... "name" : "Able 1 - Goo" }
-
Execute
Able_GET_ByExternalReferenceCode
with theable-one
ERC../Able_GET_ByExternalReferenceCode.sh able-one
This returns the
able-one
entry with theauditEvents
array, a history of the entries events, beginning with the most recent event and ending with the entry’s creation.{ ... "auditEvents" : [ { "auditFieldChanges" : [ { "name" : "name", "newValue" : "Able 1 - Goo", "oldValue" : "Able 1 - Bar" } ], "dateCreated" : "2023-05-04T05:44:41Z", "eventType" : "UPDATE" }, { "auditFieldChanges" : [ { "name" : "name", "newValue" : "Able 1 - Bar", "oldValue" : "Able 1 - Foo" } ], "dateCreated" : "2023-05-04T05:44:40Z", "eventType" : "UPDATE" }, { "auditFieldChanges" : [ { "name" : "name", "newValue" : "Able 1 - Foo" } ], "dateCreated" : "2023-05-04T05:44:37Z", "eventType" : "ADD" } ], ... "externalReferenceCode" : "able-one", "id" : 47512, ... "name" : "Able 1 - Goo" }
The
auditEvents
array includes these elements:auditFieldChanges
: The updated field, with its new and old values.dateCreated
: The time and date of the event.eventType
: The event type (e.g.,ADD
,UPDATE
,DELETE
).
-
Execute
Ables_GET_FromCompany
../Ables_GET_FromCompany.sh able-one
This returns all Able entries with an audit of their events, beginning with the most recent event.
{ ... "items" : [ { ... "auditEvents" : [ { "auditFieldChanges" : [ { "name" : "name", "newValue" : "Able 2 - Foo" } ], "dateCreated" : "2023-05-04T06:15:50Z", "eventType" : "ADD" } ], ... "externalReferenceCode" : "able-two", "id" : 47514, ... "name" : "Able 2 - Foo" }, { ... "auditEvents" : [ { "auditFieldChanges" : [ { "name" : "name", "newValue" : "Able 3 - Foo" } ], "dateCreated" : "2023-05-04T06:15:51Z", "eventType" : "ADD" } ], ... "externalReferenceCode" : "able-three", "id" : 47516, ... "name" : "Able 3 - Foo" }, { ... "auditEvents" : [ { "auditFieldChanges" : [ { "name" : "name", "newValue" : "Able 1 - Goo", "oldValue" : "Able 1 - Bar" } ], "dateCreated" : "2023-05-04T06:16:25Z", "eventType" : "UPDATE" }, { "auditFieldChanges" : [ { "name" : "name", "newValue" : "Able 1 - Bar", "oldValue" : "Able 1 - Foo" } ], "dateCreated" : "2023-05-04T06:16:24Z", "eventType" : "UPDATE" }, { "auditFieldChanges" : [ { "name" : "name", "newValue" : "Able 1 - Foo" } ], "dateCreated" : "2023-05-04T06:15:49Z", "eventType" : "ADD" } ], ... "externalReferenceCode" : "able-one", "id" : 47512, ... "name" : "Able 1 - Goo" } ], "lastPage" : 1, "page" : 1, "pageSize" : 20, "totalCount" : 3 }
Examining the GET Requests
These GET requests include the nestedFields=auditEvents
parameter in their URLs.
Able_GET_ByExternalReferenceCode
curl \
"http://localhost:8080/o/c/ables/by-external-reference-code/${1}?nestedFields=auditEvents" \
--user "test@liferay.com:learn"
Ables_GET_FromCompany
curl \
"http://localhost:8080/o/c/ables/?nestedFields=auditEvents" \
--user "test@liferay.com:learn"