SharePoint development is finally catching up with industry standards when it comes to implementing new functionality on your sites. Webhook is one of these standards that has been introduced in 2016 for SharePoint Online. It gives your organisation the ability to get notified when something happens in your list or library, but it involves a new way of processing these notifications. This session is for you if you want to learn to work with this newly introduced functionality like subscribing to a webhook, event processing, getting the latest changes, and more.
4. #SPSLondon - @eliostruyf
What are WebHooks?
• Event driven notifications AKA callbacks from the web
• Universal model used by many services: GitHub, Slack, MailChimp, …
• Pushing mechanism asynchronous!
• Implemented in various Office 365 Services
• Microsoft Graph
• Connectors
• SharePoint
6. #SPSLondon - @eliostruyf
Where can you use them?
• SharePoint
• List
• Libraries
• Microsoft Graph
• Messages, events, contacts, conversations in groups, OneDrive root items
7. #SPSLondon - @eliostruyf
The good and the bad
• WebHooks are asynchronous mechanism
• Retry mechanism
• 5 times with a delay of 5 minutes
• More secure, no event information is passed
• No support for event-ing events only RER can be used
• Add-ing, update-ing, delete-ing
• Requires some setup, but once done, it is easy to maintain
8. #SPSLondon - @eliostruyf
Remote event receivers vs WebHooks
Remote event receivers
• Synchronous (-ing) and/or async (-ed)
• One request
• One change = one request
• Changes are inside the request body
• 2 minutes to respond
• Indefinitely
• One try
WebHooks
• Async only
• Retry logic: 5 times
• Batched requests
• Only notification more secure
• 5 seconds to respond
• Needs subscription renewal
• When it fails, you can try again later
Both use the same base principle: call an external URI when something happens
10. #SPSLondon - @eliostruyf
By subscribing to a WebHook!
Notification service
1. Create a subscription
4. SharePoint responds with subscription info
11. #SPSLondon - @eliostruyf
Important things about subscribing
Subscribing: POST - /_api/web/lists/getbytitle('Title')/subscriptions
{
"resource": "https://tenant.sharepoint.com/sites/site/_api/web/lists/getbytitle('Title')",
"notificationUrl": "Your notification service URL – HTTPS is required",
"expirationDateTime": "Date value - maximum 6 months",
"clientState": "String value for validation (optional)"
}
12. #SPSLondon - @eliostruyf
Important things about subscribing
SharePoint calls your notification service:
POST - https://notification-service?validationToken={random-guid}
Respond with:
Important: notification service needs to respond in < 5 seconds
Status: 200
Body: validationtoken
18. #SPSLondon - @eliostruyf
Notification service details
• You choose the technology: Web API, Node.js, …
• Respond in < 5 seconds and with status: 200-299 range
• Retry mechanism 5 times (5 minute in between)
• Not for the validation process
• Receives minimal information, just a message “something” happened
• Service has to gather the changes from SharePoint
20. #SPSLondon - @eliostruyf
This is what you will receive
{
"value": [
{
"subscriptionId":"2e7f9cd7-5cdb-4d57-b4d5-edc083202378",
"clientState":null,
"expirationDateTime":"2017-08-16T10:38:54.3440000Z",
"resource":"465b36fc-e778-4047-8425-3f906497dfc3",
"tenantId":"9fee8694-d491-4e3e-b10b-a81ee76dfad9",
"siteUrl":"/sites/Webhooks",
"webId":"e363e4e9-0161-495f-a652-15c618e2e963“
}]
}
21. #SPSLondon - @eliostruyf
How do I know what happened?
• SPList.GetChanges method
• POST - `/_api/web/lists(guid'${resource}')/getchanges`
• Specify a change query + change token
{
"Item": true,
"Add": true,
"Update": true,
"DeleteObject": true,
"Restore": true,
"ChangeTokenStart": {
"StringValue": "1;3;465b36fc-e778-4047-8425-3f906497dfc3;636307008298500000;60877869"
}
}
ChangeQuery properties: http://elst.es/2rib2q7
22. #SPSLondon - @eliostruyf
Anatomy of the change token
1;3;465b36fc-e778-4047-8425-3f906497dfc3;636307008298500000;60877869
Version information (currently always 1)
Scope of the change. 3 = List & library changes.
Resource ID, can be retrieved from the subscription notification
Timestamp in ticks
Change number
in the event
cache table. You
can start with -1.
23. #SPSLondon - @eliostruyf
Using the change token
• Using GetChanges without ChangeToken would return everything
• By specifying a change token, you control what you need
24. #SPSLondon - @eliostruyf
Things to know about the change token
• First time, create it yourself (ex.: get all changes of the last hour)
• Per GetChanges request, you get the latest change token
• Store the latest change token, use it for the next call
{
"ChangeToken": {
"StringValue":"1;3;465b36fc-e778-4047-8425-3f906497dfc3;636307074435230000;60879219"
},
"ChangeType": 2,
"SiteId": "1432d309-9f6a-4dae-8d35-532dec332b86",
"ItemId": 3,
…
}
25. #SPSLondon - @eliostruyf
GetChanges response value
• Notice the ChangeType, it is an enumeration
• 1 = added, 2 = updated, 3 = deleted
{
"ChangeToken": {
"StringValue":"1;3;465b36fc-e778-4047-8425-3f906497dfc3;636307074435230000;60879219"
},
"ChangeType": 2,
"SiteId": "1432d309-9f6a-4dae-8d35-532dec332b86",
"ItemId": 3,
"ServerRelativeUrl":"",
…
"WebId":"e363e4e9-0161-495f-a652-15c618e2e963"
}
More information about the ChangeTypes - http://elst.es/2ruAfKn
30. #SPSLondon - @eliostruyf
Tokens, all about the OAuth tokens
• Azure AD app registration
• Generate a certificate
• SharePoint requires access tokens with appidacr property set to 2
• Application Authentication Context Class Reference
• 0 = Public client
• 1 = Identified by a client id and secret
• 2 = Identified by a certificate
31. Azure AD application manifest
Store this in a separate file (privatekey.pem)
Fingerprint is also require to get the access token
32.
33. #SPSLondon - @eliostruyf
public getAppOnlyAccessToken(config: IConfig): Promise<any> {
return new Promise((resolve, reject) => {
const certificate = fs.readFileSync(path.join(__dirname, 'privatekey.pem'), { encoding : 'utf8'});
const authContext = new adal.AuthenticationContext(config.adalConfig.authority);
authContext.acquireTokenWithClientCertificate(config.adalConfig.resource, config.adalConfig.clientID, certificate,
config.adalConfig.fingerPrint, (err, tokenRes) => {
if (err) {
reject(err);
}
const accesstoken = tokenRes.accessToken;
resolve(accesstoken);
});
});
}
Get an access token via a certificate and
private key with ADAL for JS
34. #SPSLondon - @eliostruyf
Important APIs
• Retrieve all list / library subscriptions
GET - /_api/web/lists/getbytitle('ListTitle')/subscriptions
• Update a subscription
PATCH - /_api/web/lists/getbytitle('ListTitle')/subscriptions('${subId}')
Body: { "expirationDateTime": "New expiration date" }
• Delete a subscription
DELETE - /_api/web/lists/getbytitle('ListTitle')/subscriptions('${subId}')
36. #SPSLondon - @eliostruyf
A real life setup and configuration
SPO config page
HTTP Triggered function
Queue triggered function
1. Subscribe 2. Validate
3. Trigger change
4. Notify service
5. Put notification message on a queue6. Respond with 200
Use the page to:
- Check subscriptions
- Update subscriptions
- Delete subscriptions
7. Trigger another Azure function that will do change handling
8. Retrieve latest change token10. Store latest change token
38. #SPSLondon - @eliostruyf
Recap
• Notification service has to respond in < 5 seconds
• Retry mechanism 5 times (5 minute delay)
• Not for the validation process
• Subscription expiration date: 6 months
• Create a check or renewal process in your subscription processor
• You need to ask for the changes that happened minimal
information is send
• Get the changes only what you are interested in
• No synchronous events for SPO event-ing events