SharePoint on the Graph

Matthew Barben
Driver Lane
9 min readMar 31, 2021

--

In the past few months whenever I review the REST API documentation for SharePoint, there is always this menu item on the left-hand column

Who are you V2?

This will inevitably take me through to the MSGraph — and with that, there are new libraries and new ways to sorting things out. And of course, most tutorials online take things to the ‘Hello World’ stage. For this I want to take from nil to a small node app that will:

  • Access a SharePoint site
  • Create a Folder in a Document Library
  • Create a Document in a Document Library
  • Add an entry to a list

Hopefully, once we are done we have an approach that you can take to creating a console app that will connect to the MS Graph.

Setup Application

There are going to be a couple of key links that are going to help you on your journey here:

These will give you the basis for what calls are possible and through the use of the graph explorer the confidence to test the calls to the graph.

Now at the end of this registration process, we are going to need the following outputs:

Now before we get too deep, Microsoft has done a great job document a lot of what we will need to do to register a new application.

So let's start, browse to your Azure Active Directory (portal.azure.com), and then select App Registrations and we will register our new app.

App Registrations

Given the calls we making (to specific SharePoint sites), we will need to ensure that we only select a single tenant in our app registration.

Select Single Tenant for App Registration

With the app registered we can collect the client id and the tenant id.

With app registered, collect client id and tenant id

Next, we need to generate our application secret, on the left-hand panel select Certificates & secrets and then click new client secret

Browse to Certificates & secrets and then click new client secret

With that new client secret generated we have what we need to start developing our app.

App Permissions

However, before jumping into the code right away we want to take a beat and look at what permissions we are going to need. Using the graph explorer can test the API calls that you can make again the MS Graph service. Using the default calls (Files and SharePoint) you can use the Modify Permissions tab to get a read of the permissions that you are using

For this project it will be:

  • Files.ReadWrite.All
  • Sites.Read.All
  • Sites.ReadWrite.All

This might be overkill for many situations and you are likely to need to tune this up and down.

Now that we have the permissions we need, we can add Files.ReadWrite.All Sites.Read.All and Sites.ReadWrite.All permissions to the application.

Add Permissions and then grant Admin consent

After you add your permissions you can then grant Admin consent to the permissions.

Setup SharePoint

There is not much point to all of this if we don't have a SharePoint to point at. For my example, I have set up a simple communication site with a Document Library

Document Library

In addition, I have set up a basic list that we can query

With that setup, let's proceed.

Let's write some Code

For our node project, we are going to create a console-based app that will have a menu to enable us to select the various functions we want to execute.

To connect to the MS Graph we will use the @azure/msal-node module to authenticate, and we will use that authentication method to plug into the graph client @microsoft/microsoft-graph-client , and using that graph client we are able to access the data within SharePoint.

Setup the Project

Setup your node project (do the npm init dance) and then we will install our dependencies:

npm install @azure/msal-node @microsoft/microsoft-graph-client inquirer uuid --save

Next, install the dev dependencies

npm install typescript tslint ts-node @types/inquirer @microsoft/microsoft-graph-types @types/uuid --save-dev

Setup TypeScript

Next, we set up TypeScript — now there are a bunch of ways to set this up — but for me, I tend to use the same as the previous projects however you can get away by simply using

tslint --init

This will create a tslint.json at the root of your project. Finally, we will add a tsconfig.json to the root of this project

{
"compilerOptions": {
"module": "commonjs",
"esModuleInterop": true,
"target": "esnext",
"noImplicitAny": true,
"moduleResolution": "node",
"sourceMap": true,
"outDir": "dist",
"baseUrl": ".",
"paths": {
"*": [
"node_modules/*"
]
},
"emitDecoratorMetadata": true,
"experimentalDecorators": true
},
"include": [
"src/**/*"
]
}

Update package.json

To complete the setup we want to add some additional scripts to the package.json

"prebuild": "tslint -c tslint.json -p tsconfig.json --fix",
"build": "tsc",
"dev": "nodemon --watch './src/**/*.ts' --exec ts-node ./src/index.ts",
"rundev": "ts-node ./src/index.ts"

Folder Structure

The folder structure that we will be using for this is very simple.

Folder Structure for the Project

There are a couple of things to point out:

  • The temp folder will be used to store documents that we will use to upload documents
  • and the src/environments folder will be used to store my environment variables

Custom Authentication Provider

To authenticate with the Microsoft graph in node we will use the @azure/msal-node module and the AuthenticationProvider class from the @microsoft/microsoft-graph-client module.

To start I define an interface that will contain our four key outputs from our application registration:

  • Client Id
  • Client Secret
  • Authority Endpoint
  • And Graph Endpoint

As we are creating our own custom authentication provider we will extend the existing AuthenticationProvider class. This will have two methods:

  • a contstructor method that will take the config as input and set up the default scopes
  • and a getAccessTokenmethod which will return an access token

Graph Client

Now that we have our authentication provider in place, let's plumb it into our graph client. This is a new class that we will use in our main app. For now we will only implement the following methods:

  • get — for GET requests
  • post — for POST requests
  • put — for PUT requests

The main application

For our main application, we will create a main function that will prompt the user to make a selection. In addition, we will create separate functions that will provide the functionality for the following SharePoint actions:

  • Access SharePoint site information
  • Access SharePoint list
  • Add an Item to a SharePoint list
  • Create a folder in a Document Library
  • Upload a document
The main function will prompt users for the option to select.

Next, you can run npm run dev and you should now be presented with a list of menu items.

Running the program

SharePoint Site Info

This is a nice gentle introduction. This will become the basis of a lot of future calls as it will give us the correct ids to use when traversing the MS Graph

SharePoint Site information function

Running the program and selecting the Access SharePoint Information option should return the following:

{
'@odata.context': 'https://graph.microsoft.com/v1.0/$metadata#sites/$entity',
createdDateTime: '2021-02-10T03:10:03.59Z',
description: 'SampleSharePoint',
id: 'sample.sharepoint.com,42b6123-1234-1234-b1d2-d0f912c2ed24,3f12c123-bd12-12a3-12fe-123d1c123d12',
lastModifiedDateTime: '2021-03-29T23:01:55Z',
name: 'PigglesSharePoint',
webUrl: 'https://sample.sharepoint.com/sites/SampleSharePoint',
displayName: 'SampleSharePoint',
root: {},
siteCollection: { hostname: 'sample.sharepoint.com' }
}

Access SharePoint list

Next, we build upon that and we access a SharePoint list. This time we use the site id got by using: await graph.get(sharePointUrl);

Using that id, we can then get back the array of all the lists (which is returned as an array). We loop through that array to return the list information.

Access SharePoint list function

Add Item to SharePoint list

Now that we have the List Id we can expand this to add a new list item to the SharePoint list.

The format for the body of this request is simple:

const listItem = {
fields: {
Title: 'SharePoint using Graph',
Value: uuidv4()
}
};

For the title we are using the uuid library to add some uniquness to the entry.

Add List Item function

And when we run the app again get select Add item to SharePoint list we get our new list item 🥰

Screen shot with new list item

Create Folder in Document Library

Now we are on to the Document Libary parge of the API. Now this is all based on the OneDrive API. But instead of using a url like this:

https://graph.microsoft.com/v1.0/me/drive/root/children

we replace the ‘me’ in the url with the SharePoint site it.

https://graph.microsoft.com/v1.0/sites/sample.sharepoint.com,siteid,documentlibraryid/drive/root/children

To add a new folder, the body will be simple and as with the previous example we are using uuid to create a unique folder.

const foldername = {
"name": uuidv4(),
"folder": {}
};

Below is the function

Now we are run that again and this time we can see a folder created successfully in the document library.

Document Library with the new folder

Upload a Document to Document Library

The approach that you take to uploading documents using the MS Graph API will greatly depend on the size of the files. For documents that are smaller than 4 MB, you can use a standard put. For larger documents, you will need to create an upload session, and in that session, you can only upload 60 MB chunks at a time.

Happily, the MS Graph client allows some additional methods that will help us out.

First of all, let's sort out the small/large file problem — for this we get the stats from the file we are uploading

const fSize = statSync(uploadFile);

Then you can check the file size and create your put statement:

Now for the large file we will need to two new methods to our MS Graph Client:

pathToFile — this will take a filepath (String), and filename (String) as inputs and return a File object. The methods that we will be using will need this to ensure that the larger file gets chunked correctly.

addLargeFile — this method will take the URL, filename, file size, and file object and use the LargeFileUploadTask to create the session and upload the file to SharePoint

With that in place, we can complete our else statement (i.e. handle files over 4 Mb in size).

const largeFileUploadSessionUrl = `/sites/${getSiteId.id}/drive/items/${getRootId.id}:/${fileName}:/createUploadSession`const largeFile = graph.pathToFile(uploadFile, fileName);
const largeFileUpload = await graph.addLargeFile(largeFileUploadSessionUrl, fileName, fSize.size, largeFile);

Below is the complete function

And finally our updated Client

And what is success without a screenshot 😍😍

All Files Upload — Happy days

Wrapping up

In summing up the biggest challenges here was getting the initial authentication behaving constantly, and then after that getting the document upload working (especially with larger files).

Hopefully, this helps the next person who needs one place to run through everything.

Source code for the complete project is below — have fun 😁

Connect with Driver Lane on Twitter, and LinkedIn, or directly on our website.

--

--