As part of the Open Exchange competition Salford Royal (Dean White and Mark O'Reilly) developed a REST API for sharepoint as a template that works but can also be a starting point to your own Rest Applications
Prerequisites
This is using the v1 REST sharepoint API you need a tennant id, client id, client secret and tennant name
Setup
Configure an OAuth server
.png)
The code in the middle is the tennant ID
Create a client config name as whatever you want
.png)
Set up the oauth client replacing your server ip with the ip of the server you are on (not the VIP address- if not part of a VIP localhost may work)
.png)
Add in client credentials
change over the settings on SharepointRESTConnector like HTTPSERVER,SHAREPOINT-SITENAME- SHAREPOINT FILEPATH- SSL (blank up to 1.3) params replace the tennant name and tennant id.
Code
SharePointOnlineRESTOperation
OAuth Scope isn't user in this example but left here as a template if you need it for other rest implementation
It uses and builds on default rest Set tSC=..AddAccessToken(.tHttpRequest) which manages the token and will pass through any additional properties required for the API. For sharepoint API it requires a resource and this gets added in the settings in the comment notes
Get File list
Will call list of files in the folder you have. It can run the time since you last downloaded or all files It queries ens header.
It calls the GetFolderByServerRealativeURL
Set ..Adapter.URL="/sites/"_$$$URLENCODE(..SharepointSitename)_"/_api/web/GetFolderByServerRelativeUrl('"_$$$URLENCODE(..SharepointFilePath)_"')/Files"_filter Set ..Adapter.URL="/sites/"_$$$URLENCODE(..SharepointSitename)_"/_api/web/GetFolderByServerRelativeUrl('"_$$$URLENCODE(..SharepointFilePath)_"')/Files"_filter
The response gets read by the processer.
It all sends http messages like POSTMAN would
A Constuct response method was taken from the generic operation intersystems had written to return http responses
DeleteFile
Calls a delete send request to getfolderbyserverrelativeurl/files
key lines below
Set ..Adapter.URL="/sites/"_$$$URLENCODE(..SharepointSitename)_"/_api/web/GetFolderByServerRelativeUrl('"_$$$URLENCODE(..SharepointFilePath)_"')/Files('"_$$$URLENCODE(pRequest.FileName)_"')"
Set tSC=..AddAccessToken(.tHttpRequest)
s tSC = ..SendRequest(.tHttpResponse,send,tHttpRequest, .pResponse)
Quit ..constructResponse(.tHttpResponse,.pResponse)
DownloadFile
if it is a Ens.StringContainer (you could make this a bespoke message extending this of like Messages.DownloadSharpointFile) it reads the name and then sends the name in the api url. it reads the response pack and will add to a steamcontainer the binary stream. As always we create the stream and then package it up into the streamcontainer.
Key code below (changed some s to set for display here)
set binaryStream =##Class(%Stream.FileBinary).%New()
Set tSC=..AddAccessToken(.tHttpRequest)
Set ..Adapter.URL="/sites/"_$$$URLENCODE(..SharepointSitename)_"/_api/web/GetFolderByServerRelativeUrl('"_$$$URLENCODE(..SharepointFilePath)_"')/Files('"_$$$URLENCODE(pRequest.StringValue)_"')/OpenBinaryStream()"
Set tHttpResponse = ##class(%Net.HttpResponse).%New()
set send="GET"
set tSC = ..SendRequest(.tHttpResponse,send,tHttpRequest, .pResponse)
set pDownloadResponse =##Class(Ens.StreamContainer).%New(binaryStream)
set pDownloadResponse.OriginalFilename=pRequest.StringValue
Add File
GetFolderByServerRelativeUrl/filepath/Files/add(url=filename,overwrite?)
Key lines
Set ..Adapter.URL="/sites/"_$$$URLENCODE(..SharepointSitename)_"/_api/web/GetFolderByServerRelativeUrl('"_$$$URLENCODE(..SharepointFilePath)_"')/Files/add(url='"_fn_"',overwrite="_$$$URLENCODE(..OverwriteExistingFile)_")"
Set tSC=..AddAccessToken(.tHttpRequest)
s tHttpRequest.EntityBody=##Class(%Stream.FileBinary).%New()
s sc=tHttpRequest.EntityBody.CopyFromAndSave(pFileToUpload.Stream)
Set tHttpResponse = ##class(%Net.HttpResponse).%New()
S send="POST"
s tSC = ..SendRequest(.tHttpResponse,send,tHttpRequest, .pResponse)
Send Request
This does the sending of any request expecting a http response.
Does the handing of responses and reuns a ENSLIB.HTTP.GenericMessage. A lot of headers come back and there is a check box to simplify the response back to just be error code and data.
Construct Response
Used from elsewhere in TIE not original code in this method
AddAccessToken
This was the real learning. this is default type code to use the intersystems OAuth settings and not hardcode this each time we need to use it.
It's all built around three calls
is authorised and
Set isAuthorised = ##class(%SYS.OAuth2.AccessToken).IsAuthorized(..OAuthClientApplicationName,sessionId,..OAuthScope,.accessToken,,.responseProperties,.error)
Get access token
Set tSC = ##class(%SYS.OAuth2.Authorization).GetAccessTokenClient(..OAuthClientApplicationName,..OAuthScope,.properties,.error,.sessionId)
and a Add token which adds it to the header - unfortunetly it doesn't look like it could add to the body if credential is required there by other apis
Set tSC = ##class(%SYS.OAuth2.AccessToken).AddAccessToken(pHttpRequest,sendType,,..OAuthClientApplicationName,sessionId)
The additional bit is the Sharepoint API requires a resource. Now we have generalised this to use JSON so if you need any other parameters we thought lets add it as JSON so we can reuse the template in the future.
it adds it to the string object that the properties used. its like an array serialised string or something
s paramsarr = [].%FromJSON(..Params)
s iterator = paramsarr.%GetIterator()
s properties=""
While iterator.%GetNext(.key,.value)
{
s properties(key)=value
}
Example traces
Getting file list
.png)
Downloading files
.png)
deleting files
is if you tick this box
.png)
Adding files
.png)
Thanks to @Dean White
https://youtu.be/485dTXYp2BU
Update - add YouTube link and fix open exchange link