Change API
Getting changes, synchronisation scenarios
When it comes to synchronization or delta processing Change API is for the rescue. There is no need in any sort of logic that used modified date comparison to detect what has been changed since the last processing time. There is no need to wait until the search crawl is done to check changes through web or site collection. And not only these benefits but also tracking permissions changes restores from recycle bin, system updates and much more.
Changes API is what is used together with Webhooks (in SPO), by having a context (scope) and change token(s) you can easily retrieve what has been changed and run the custom logic based on the nature of changes.
Changes can be requested from within different scopes: lists, webs, sites, etc. Change API operates change tokens to establish start and end anchors.
Change tokens received from a specific entity type (e.g. Site) can't be used with another entity type (e.g. List) while sending change query.

Getting current change token

1
siteChangeToken, err := sp.Site().Changes().GetCurrentToken()
2
if err != nil {
3
log.Fatal(err)
4
}
5
6
fmt.Printf("Site change token: %s\n", siteChangeToken)
7
8
webChangeToken, err := sp.Web().Changes().GetCurrentToken()
9
if err != nil {
10
log.Fatal(err)
11
}
12
13
fmt.Printf("Web change token: %s\n", webChangeToken)
14
15
list := sp.Web().GetList("Lists/MyList")
16
listChangeToken, err := list.Changes().GetCurrentToken()
17
if err != nil {
18
log.Fatal(err)
19
}
20
21
fmt.Printf("List change token: %s\n", listChangeToken)
22
23
// Site change token:
24
// 1;1;afbc6f5a-65b3-4b64-9f40-885d8d772c8c;637138201430100000;64696075
25
// Web change token:
26
// 1;2;7e084f68-c401-4910-b75e-4347c7848965;637138201430100000;64696075
27
// List change token:
28
// 1;3;3b542696-5863-4ff7-bb90-8224e9e8adb9;637138201430100000;64696075
Copied!

Getting changes

Knowing what root entities' token(s) you have the specific changes query can be crafted and sent, e.g.:
1
list := sp.Web().GetList("Lists/MyList")
2
listChangeToken, _ := list.Changes().GetCurrentToken()
3
list.Items().Add([]byte(`{"Title":"New item"}`))
4
// error handling is omitted -- adding a dummy item to receive changes result
5
6
changes, err := list.Changes().GetChanges(&api.ChangeQuery{
7
ChangeTokenStart: listChangeToken,
8
List: true,
9
Item: true,
10
Add: true,
11
})
12
if err != nil {
13
log.Fatal(err)
14
}
15
16
for _, change := range changes.Data() {
17
fmt.Printf("%+v\n", change)
18
}
Copied!
Change results are strongly typed with Gosip's API, the changes variable in the sample is an array of api.ChangeInfo struct pointers.
Change into struct contains the following properties:
1
type ChangeInfo struct {
2
ChangeToken *StringValue
3
ChangeType int
4
Editor string
5
EditorEmailHint string
6
ItemID int
7
ListID string
8
ServerRelativeURL string
9
SharedByUser string
10
SharedWithUsers string
11
SiteID string
12
Time time.Time
13
UniqueID string
14
WebID string
15
}
Copied!
ChangeType is an important piece of information, it's an enumerator describing a nature of a change. See more.
Change API doesn't return what specifically was changed but only where it was changed. For instance, when an item is changed the API will return its identities information but not the metadata.
In a synchronization scenario or a Webhook after getting information which items are changed the corresponding request(s) should be sent for getting specifics.

Change query

When getting the changes the API requires some clarifications about what exactly should be retrieved. This is defined within a change query which is implemented api.ChangeQuery struct.
Property
Description
ChangeTokenStart
Specifies the start date and start time for changes that are returned through the query
ChangeTokenEnd
Specifies the end date and end time for changes that are returned through the query
Add
Specifies whether add changes are included in the query
Alert
Specifies whether changes to alerts are included in the query
ContentType
Specifies whether changes to content types are included in the query
DeleteObject
Specifies whether deleted objects are included in the query
Field
Specifies whether changes to fields are included in the query
File
Specifies whether changes to files are included in the query
Folder
Specifies whether changes to folders are included in the query
Group
Specifies whether changes to groups are included in the query
GroupMembershipAdd
Specifies whether adding users to groups is included in the query
GroupMembershipDelete
Specifies whether deleting users from the groups is included in the query
Item
Specifies whether general changes to list items are included in the query
List
Specifies whether changes to lists are included in the query
Move
Specifies whether move changes are included in the query
Navigation
Specifies whether changes to the navigation structure of a site collection are included in the query
Rename
Specifies whether renaming changes are included in the query
Restore
Specifies whether restoring items from the recycle bin or from backups is included in the query
RoleAssignmentAdd
Specifies whether adding role assignments is included in the query
RoleAssignmentDelete
Specifies whether adding role assignments is included in the query
RoleDefinitionAdd
Specifies whether adding role assignments is included in the query
RoleDefinitionDelete
Specifies whether adding role assignments is included in the query
RoleDefinitionUpdate
Specifies whether adding role assignments is included in the query
SecurityPolicy
Specifies whether modifications to security policies are included in the query
Site
Specifies whether changes to site collections are included in the query
SystemUpdate
Specifies whether updates made using the item SystemUpdate method are included in the query
Update
Specifies whether update changes are included in the query
User
Specifies whether changes to users are included in the query
View
Specifies whether changes to views are included in the query
Web
Specifies whether changes to Web sites are included in the query

Pagination

Sometimes it can be lots of changes since a provided token. Gosip implements pagination helper using "jumping" between different change tokens under the hood. When last change item's token is used as a start token to get the "next page". This approach is used in GetNextPage:
1
changesFirstPage, _ := list.Changes().Top(100).GetChanges(&ChangeQuery{
2
ChangeTokenStart: token,
3
List: true,
4
Item: true,
5
Add: true,
6
})
7
8
changesSecondPage, _ := changesFirstPage.GetNextPage()
Copied!

Summary

Change API is a powerful mechanism and a robust way for processing delta changes that can and should be used in advanced and optimised synchronizations and business processes withing external workers.
Last modified 1yr ago