Article
· Dec 13 5m read

SharePoint/ SPO API with intersystems

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

 

The code in the middle is the tennant ID 

Create a client config name as whatever you want 

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) 

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 

/// For SPO the Params should be {"resource":"00000003-0000-0ff1-ce00-000000000000/{TennantName}.sharepoint.com@{TennantID}"} <p>
/// 00000003-0000-0ff1-ce00-000000000000 is the ResourceID asigned to SPO by Microsoft, and should not change <p>
/// {TennantName} should be changed to the same as the HTTP server e.g.intersystems.sharepoint.com <p>
/// {TennantID} is the ID for your server name tennancy 

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


        ;The default for sslConfiguration comes from the OAuth2.Client instance.        
        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

Downloading files

deleting files

is if you tick this box 

Adding files

Thanks to @Dean White 
 

https://youtu.be/485dTXYp2BU

Update - add YouTube link and fix open exchange link 

Discussion (1)1
Log in or sign up to continue