Create your own image proxy server (Cloudinary)
Background
We are able to get the image data from microsoft 365 sharepoint by using GraphApi. Here it is the data format that we can get from the API.
{
'@odata.context': "https://graph.microsoft.com/v1.0/$metadata#sites('your-tenant-name.sharepoint.com%2Cbdaafbd4-08f0-421c-877e-4b87dc459784%2C22c9a737-a9b6-4279-885e-2231d39a0627')/drives('drive-id')/root/$entity",
'@microsoft.graph.downloadUrl': 'image-download-url',
createdDateTime: '2023-02-25T11:29:32Z',
eTag: '"{816F406D-5FEA-4C16-A59D-38642DF4D422},1"',
id: '01YNQIXNTNIBXYD2S7CZGKLHJYMQW7JVBC',
lastModifiedDateTime: '2023-02-25T11:29:32Z',
name: 'TainanView2.jpg',
webUrl: 'https://your-tenant-name.sharepoint.com/sites/your-sharepoint-site-name/Shared%20Documents/TainanView2.jpg',
cTag: '"c:{816F406D-5FEA-4C16-A59D-38642DF4D422},2"',
size: 101248,
createdBy: {
user: {
email: '[email protected]',
id: '9cb2608c-4df5-4388-ac85-f8c9fac6f537',
displayName: 'Eric Lee'
}
},
lastModifiedBy: {
user: {
email: '[email protected]',
id: '9cb2608c-4df5-4388-ac85-f8c9fac6f537',
displayName: 'Eric Lee'
}
},
parentReference: {
driveType: 'documentLibrary',
driveId: 'drive-id',
id: '01YNQIXNV6Y2GOVW7725BZO354PWSELRRZ',
path: '/drives/drive-id/root:',
siteId: 'bdaafbd4-08f0-421c-877e-4b87dc459784'
},
file: {
mimeType: 'image/jpeg',
hashes: { quickXorHash: 'HXxjKmWVs6vtfoKXupU3C5wyaks=' }
},
fileSystemInfo: {
createdDateTime: '2023-02-25T11:29:32Z',
lastModifiedDateTime: '2023-02-25T11:29:32Z'
},
image: { height: 720, width: 1280 },
shared: { scope: 'users' }
}
As can be seen, here are two relavent fields, @microsoft.graph.downloadUrl
and webUrl
.
@microsoft.graph.downloadUrl
is the url that we can download the image directly.webUrl
is the url that we can view the image in the browser.
OK, you might think we can simply just make use of the webUrl
to display the image in whatever web based application.
However, No, we can't. You will realize that it requires the login to microsoft 365 account to view the image.
So, what we can do is to create a proxy server to download the image from @microsoft.graph.downloadUrl
and return the image data to the client.
In this article, we will create a simple image proxy server to process the image from Microsoft 365.
The following diagram shows the architecture of the image proxy server.
loading...Scafold the project
We will make use of @colorfullife/ms365-graph-api-auth
package to manipulate sharepoint data.
You can checkout the following video for the detail usage of the package.
After initialize the node project by yarn or npm init. We also need some more dependencies to create the express image process server
"dependencies": {
"@azure/msal-node": "^1.14.1",
"axios": "^1.0.0"
},
"devDependencies": {
"@types/node": "^18.14.1",
"dotenv": "^16.0.3",
"tsup": "^6.6.3"
},
Then we can create the scripts in package.json
to build and run the project.
"scripts": {
"build": "rm -rf dist/ && tsup src/index.ts --format cjs,esm --dts",
"start": "yarn build && node dist/index.js"
},
Create the image proxy server
We will create the image proxy server in src/index.ts
.
import express from "express";
import https from "https";
import { getAccessToken, GraphApiQuery } from "@colorfullife/ms365-graph-api-auth";
require("dotenv").config();
const app = express();
app.get("/:imageName", async (req, res) => {
const { imageName } = req.params;
const authResponse = await getAccessToken(process.env.CLIENT_ID!, process.env.CLIENT_SECRET!, process.env.TENANT_ID!);
if (!authResponse) return res.status(500).send({ error: "Could not get access token" });
const query = new GraphApiQuery(authResponse.accessToken);
const mySite = await query.getSites(process.env.SITE_NAME!);
const drive = await query.getDrives(mySite.value[0].id);
const image = await query.getDriveItemByFileName(mySite.value[0].id, drive.value[0].id, imageName);
const imageDownloadUrl = image["@microsoft.graph.downloadUrl"];
https
.get(imageDownloadUrl, (response) => {
// Set the response headers to indicate that this is an image file
res.setHeader("Content-Type", "image/jpeg");
// Pipe the file stream to the response object to serve the file as an image
response.pipe(res);
})
.on("error", (err) => {
console.log({ err: err.message });
res.status(500).send("Cannot get image");
});
});
app.listen(3000, () => {
console.log("Server running on port 3000");
});
In the above code, we will get the access token by getAccessToken
function from @colorfullife/ms365-graph-api-auth
package.
Then we will get the image data by getDriveItemByFileName
function from @colorfullife/ms365-graph-api-auth
package.
Finally, we will download the image data from @microsoft.graph.downloadUrl
and return the image data to the client.
Run the image proxy server
We will need the credentials of the Microsoft 365 application.
So we will create a .env
file to store the credentials.
TENANT_ID=your-tenant-id
CLIENT_ID=your-client-id
CLIENT_SECRET=your-client-secret
SITE_NAME=your-site-name
If you are not sure how to get the credentials, you can checkout the video in above info section.
Then we can run the image proxy server by yarn start
or npm start
.
After seeing the following lines showing on the console, it means the image proxy server is up and running.
yarn run v1.22.19
$ yarn build && node dist/index.js
$ rm -rf dist/ && tsup src/index.ts --format cjs,esm --dts
CLI Building entry: src/index.ts
CLI Using tsconfig: tsconfig.json
CLI tsup v6.7.0
CLI Target: es6
CJS Build start
ESM Build start
CJS dist/index.js 7.75 KB
CJS ⚡️ Build success in 201ms
ESM dist/index.mjs 7.08 KB
ESM ⚡️ Build success in 202ms
DTS Build start
DTS ⚡️ Build success in 1926ms
DTS dist/index.d.ts 12.00 B
Server running on port 3000
Then we will be able to access the image by http://localhost:3000/your-image-name.jpg
.
Congratulations!!! We now have a image proxy server to process the image with Microsoft 365 sharepoint as backend storage.