Creating a site specific SharePoint REST API to work with lists and list items without Azure or Microsoft Graph.
1. App Registration
Go to the site where you want to create API access, then add /_layouts/15/appregnew.aspx
to the end so that your entire URL looks like this:
https://[tenant].sharepoint.com/sites/TestCommunication/_layouts/15/appregnew.aspx
- Click the two generate buttons to generate a Client ID and Client Secret. Take note of them as we'll need it later on.
- Fill in the other details on the page.
- Click Create
2. App Permissions
Now we need to assign permissions for this app. In the same site URL, add /_layouts/15/appinv.aspx
so that your entire URL looks like:
https://[tenant].sharepoint.com/sites/TestCommunication/_layouts/15/appinv.aspx
In the App ID text box, enter the Client ID generated from the previous step and click the Lookup button. Then, in the permission request XML text area, paste the following:
<AppPermissionRequests AllowAppOnlyPolicy="true">
<AppPermissionRequest Scope="http://sharepoint/content/sitecollection/web" Right="FullControl" />
</AppPermissionRequests>
Click Create and a confirmation page will ask if you want to trust the app you just created. Click Trust It.
3. Obtaining the Tenant ID
In your browser, navigate to the following URL (remember to put your own tenant name):
https://login.microsoftonline.com/[tenant].onmicrosoft.com/.well-known/openid-configuration
You should get the JSON response back in the browser window. Take a look at the URL value for "token_endpoint" and the tenant_id is between .com and oauth2
We have just about everything we need to start constructing our HTTP requests. We'll be using the requests Python library to get an access_token and start the fun stuff.
4. Python 🐍
Access Token
We have to construct a POST request to get an access token to start working with the API. This includes all of the data we obtained in the previous steps.
client_id = 'xxxx-xxxxx-xxxxxx-xxxx'
client_secret = 'xxxxxxxxxxxxxxxxxx'
tenant = 'tenant' # e.g. https://tenant.sharepoint.com
tenant_id = 'xxxx-xxx-xxxxx-xxx-xxxxx'
client_id = client_id + '@' + tenant_id
data = {
'grant_type':'client_credentials',
'resource': "00000003-0000-0ff1-ce00-000000000000/" + tenant + ".sharepoint.com@" + tenant_id,
'client_id': client_id,
'client_secret': client_secret,
}
client_id is being overwritten. It is the client ID we got from the first step AND the tenant_id we got in the last step, joined by an '@'
With this data, we need to make a POST request to
https://accounts.accesscontrol.windows.net/tenant_id/tokens/OAuth/2
headers = {
'Content-Type':'application/x-www-form-urlencoded'
}
url = "https://accounts.accesscontrol.windows.net/tenant_id/tokens/OAuth/2"
r = requests.post(url, data=data, headers=headers)
json_data = json.loads(r.text)
print(json_data)
{
'token_type': 'Bearer',
'expires_in': '86399',
'not_before': '1605580031',
'expires_on': '1605666731',
'resource': '00000003-0000-0ff1-ce00-000000000000/tenant.sharepoint.com@tenant_id',
'access_token': 'eyJ0eyJhdWQiOiIwMDAwMDAw......'
}
The json_data line loads the JSON text response as a dictionary where we can grab the access token value by it's key json_data['access_token']
. The access_token gets added in all subsequent API calls. The response also gives you some expiration data at which time you'll need to re-authenticate. The white-space after Bearer is important!
headers = {
'Authorization': "Bearer " + json_data['access_token'],
'Accept':'application/json;odata=verbose',
'Content-Type': 'application/json;odata=verbose'
}
Get List Items
We're finally ready to make a GET request to the SharePoint list endpoint URL which will return all items in a list. In this site there is a List called Customers with a few items:
With a list named 'Customers' the endpoint to get the list items looks like this:
url = "https://tenant.sharepoint.com/sites/TestCommunication/_api/web/lists/getbytitle('Customers')/items"
l = requests.get(url, headers=headers)
Nestled in the JSON response is an array of JSON objects which contains all of the List item data, including meta data from SharePoint.
print(l.text)
{...
[
{
...
"FileSystemObjectType": 0,
"Id": 3,
"ServerRedirectedEmbedUri": null,
"ServerRedirectedEmbedUrl": "",
"ContentTypeId": "0x01006F79CB39F79A2E4AA6B7C3B0B782C524",
"Title": "UI",
"ComplianceAssetId": null,
"Name": "John Doe",
"Message": "Please call later",
"ID": 3,
"Modified": "2020-11-17T01:52:52Z",
"Created": "2020-11-16T18:38:45Z",
"AuthorId": 7,
"EditorId": 7,
"OData__UIVersionString": "1.0",
"Attachments": false,
"GUID": "d9c-xxxxx-cx-x-c"
...
},
]
...}
Add List Item
To add data to the list, POST to the same URL and include the necessary data:
# If your list name is Products then your value
# will be "SP.Data.ProductsListItem"
data = '''{ "__metadata": {"type": "SP.Data.CustomersListItem"},
"Title": "PythonAPI",
"Name": "Mr Snake",
"Message": "Hello from Python"
}'''
url = "https://tenant.sharepoint.com/sites/TestCommunication/_api/web/lists/getbytitle('Customers')/items"
p = requests.post(url, headers=headers, data=data)
> print(p)
> <Response [201]>
Other Ideas
- Need to post simple data to a SharePoint list? Use a PowerAutomate Webhook response instead! Once you create the flow and define JSON schema it is expecting, Microsoft will give you a URL.
Comments
comments powered by Disqus