Skip to content

Instantly share code, notes, and snippets.

@PokerGuy
Last active June 4, 2024 08:48
Show Gist options
  • Save PokerGuy/5cdfc4ef146ce6b535bfd8e13469a2ab to your computer and use it in GitHub Desktop.
Save PokerGuy/5cdfc4ef146ce6b535bfd8e13469a2ab to your computer and use it in GitHub Desktop.
Push a file to SharePoint
const push = async (file, fileName) => {
const client = new aws.SecretsManager();
const spURL = `https://<your site>.sharepoint.com/sites/<your specific subsite>/_api/web/GetFolderByServerRelativeUrl('Documents')/Files/Add(url='${fileName}', overwrite=true)`;
try {
const data = await client.getSecretValue({ SecretId: '<whatever you called your secret>' }).promise();
const secret = JSON.parse(data.SecretString).<whatever you called your secret>;
const getToken = await axios.post('https://accounts.accesscontrol.windows.net/<sharepoint resource id>/tokens/OAuth/2',
querystring.stringify({
grant_type: 'client_credentials',
client_id: '<ask your sharepoint person for this it's a something@tenant id>',
client_secret: secret,
resource: '<ask your sharepoint person>'
}), {
headers: {
"Content-Type": "application/x-www-form-urlencoded"
}
}
)
const accessToken = getToken.data.access_token;
const getRequestDigest = await axios.post('https://<your site>.sharepoint.com/sites/<your specific subsite>/_api/contextinfo', {}, {
headers: {
"Authorization": `Bearer ${accessToken}`,
}
})
const formDigestValue = getRequestDigest.data.FormDigestValue;
await axios.post(spURL, file, {
maxBodyLength: Infinity,
maxContentLength: Infinity,
headers: {
'Authorization': `Bearer ${token}`,
'X-RequestDigest': formDigestValue
}
})
logger.info("Success");
} catch (e) {
logger.error(e);
}
}
// If you are reading a file from a disk instead of having bytes like this example, you can replace the file in line 27 with something like Buffer.from(fs.readFileSync('./filename'))
@AlvBarros
Copy link

Thanks!

@suvro2711
Copy link

suvro2711 commented Jul 21, 2022

What is the type of the "file" object? can you please show the object? is it formdata ? binary? string?

@ChannyAzar
Copy link

Hi, thanks.
It works for me also without the second step - getRequestDigest. Looks like we don't need X-RequestDigest header in the upload request.

@ryust-ax
Copy link

ryust-ax commented Feb 13, 2023

This definitely helped get me in the right direction w/ axios; however, I think it might be simpler?, at least different in some cases like below.
At least it's not dealing with the digest detail which I don't fully understand; nor deal with the max*Length values.

import * as fs from 'fs';

    const tokenEndpoint = https://login.microsoftonline.com/_your_azure_tenant_id_/oauth2/v2.0/token
    const tokenResponse = await axios({
      method: "post",
      url: tokenEndpoint,
      data: qs.stringify({
        grant_type: "client_credentials",
        client_id: clientId,
        client_secret: clientSecret,
        scope: https://graph.microsoft.com/.default,
      }),
      headers: {
        "Content-Type": `application/x-www-form-urlencoded`,
      },
    });

    const msService = "https://graph.microsoft.com/v1.0";
    const driveId = ...previous request to get a site or drive id...
    const documentPathName = "sampleSharepointFolder/some-upload-name.docx";
    const binaryContent = fs.createReadStream("someLocalFolder/some-local-name.docx");
    const endpoint = `drives/${driveId}/items/root:/${documentPathName}:/content`;
    const url = new URL(apiPath, msService);
    const uploadResponse = await axios({
      method: "put",
      url: url,
      data: binaryContent,
      headers: {
          "Content-Type": `application/xml`,
          'Authorization': `Bearer ${tokenResponse .data.access_token}`,
      },
    });

Hopefully that all makes sense. I've compiled the above code as drawn from a couple different abstracted objects and envvar constants as part of my projects code rather than a simple async anonymous function as the OP but hopefully it might help someone. I tried got at first but it got annoyingly complicated and axios turned out to be simpler.
One note: Those :/ and :/ portions of the URL do actually matter. My initial attempts with just GET or POST using got and then axios suggested they were artifacts of MS documentation but at least in this case they do matter.

@hamzaarhandouri
Copy link

i don't know who you are but i really want to thank you for help you just saved me without even notice thanks again <3

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment