docs.sheetjs.com/docz/docs/03-demos/09-cloud/12-azure.md

234 lines
6.5 KiB
Markdown
Raw Normal View History

2022-08-21 19:43:30 +00:00
---
title: Azure Cloud Services
2023-02-28 11:40:44 +00:00
pagination_prev: demos/local/index
pagination_next: demos/extensions/index
2022-08-21 19:43:30 +00:00
---
2023-04-27 09:12:19 +00:00
import current from '/version.js';
2023-04-29 11:21:37 +00:00
import CodeBlock from '@theme/CodeBlock';
2023-04-27 09:12:19 +00:00
2022-08-21 19:43:30 +00:00
Azure is a Cloud Services platform which includes traditional virtual machine
support, "Serverless Functions", cloud storage and much more.
:::caution
Azure iterates quickly and there is no guarantee that the referenced services
will be available in the future.
:::
This demo focuses on two key offerings: cloud storage ("Azure Blob Storage")
and the "Serverless Function" platform ("Azure Functions").
2022-08-22 00:39:07 +00:00
:::note
2023-04-29 11:21:37 +00:00
This was tested on 2023 April 29.
2022-08-22 00:39:07 +00:00
:::
2022-08-21 19:43:30 +00:00
## Azure Functions
This discussion focuses on the "HTTP Trigger" function type.
:::info
To enable binary data processing, a setting must be changed in `function.json`:
```json title="function.json"
{
"bindings": [
{
"type": "httpTrigger",
"direction": "in",
//highlight-next-line
"dataType": "binary",
"name": "req",
```
:::
### Reading Data
`formidable` expects a stream and Azure does not present one. It can be made:
```js
const XLSX = require('xlsx');
const formidable = require('formidable');
const Readable = require('stream').Readable;
/* formidable expects the request object to be a stream */
const streamify = (req) => {
if(typeof req.on !== 'undefined') return req;
const s = new Readable();
s._read = ()=>{};
s.push(Buffer.from(req.body));
s.push(null);
Object.assign(s, req);
return s;
};
module.exports = (context, req) => {
const form = new formidable.IncomingForm();
form.parse(streamify(req), (err, fields, files) => {
/* grab the first file */
var f = files["upload"];
if(!f) {
context.res = { status: 400, body: "Must submit a file for processing!" };
} else {
/* file is stored in a temp directory, so we can point to that and read it */
const wb = XLSX.read(f.filepath, {type:"file"});
/* generate CSV from first sheet */
const csv = XLSX.utils.sheet_to_csv(wb.Sheets[wb.SheetNames[0]]);
context.res = { status: 200, body: csv };
}
context.done();
});
}
```
### Writing Data
The `body` property can be a Buffer, like those generated by `XLSX.write`:
```js
const XLSX = require('xlsx');
module.exports = (context, req) => {
// generate XLSX file in a Buffer
var ws = XLSX.utils.aoa_to_sheet(["SheetJS".split(""), [5,4,3,3,7,9,5]]);
var wb = XLSX.utils.book_new(); XLSX.utils.book_append_sheet(wb, ws, "Data");
// highlight-next-line
var buf = XLSX.write(wb, {type: "buffer", bookType: "xlsx"});
// Set the body and Content-Disposition header
// highlight-start
context.res = {
status: 200,
headers: { "Content-Disposition": `attachment; filename="SheetJSAzure.xlsx";` },
body: buf
};
// highlight-end
context.done();
};
```
### Demo
2023-04-29 11:21:37 +00:00
<details open><summary><b>Complete Example</b> (click to show)</summary>
2022-08-21 19:43:30 +00:00
0) Review the quick start for JavaScript on Azure Functions. This involves
installing the Azure Functions Core Tools and other dependencies.
1) Create a new project and install dependencies:
2023-04-29 11:21:37 +00:00
<CodeBlock language="bash">{`\
2022-08-21 19:43:30 +00:00
func init sheetjs-azure --worker-runtime node --language javascript
cd sheetjs-azure
2023-04-29 11:21:37 +00:00
npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz formidable`}
</CodeBlock>
2022-08-21 19:43:30 +00:00
2) Create a new "HTTP Trigger" function:
```bash
func new --template "Http Trigger" --name SheetJSAzure
```
3) Edit `SheetJSAzure/function.json` to add the `dataType: "binary"` property:
```js title="SheetJSAzure/function.json"
"direction": "in",
// highlight-next-line
"dataType": "binary",
"name": "req",
```
2023-04-29 11:21:37 +00:00
4) Download [`SheetJSAzure/index.js`](pathname:///aws/index.js):
2022-08-21 19:43:30 +00:00
2023-04-29 11:21:37 +00:00
```bash
curl -L -o SheetJSAzure/index.js https://docs.sheetjs.com/azure/index.js
2022-08-21 19:43:30 +00:00
```
5) Test locally with `npm start`
To test uploads, download <https://sheetjs.com/pres.numbers> and run:
```bash
2023-04-29 11:21:37 +00:00
curl -LO https://sheetjs.com/pres.numbers
2022-08-21 19:43:30 +00:00
curl -X POST -F "upload=@pres.numbers" http://localhost:7071/api/SheetJSAzure
```
2023-05-03 03:40:40 +00:00
To test downloads, access `http://localhost:7071/api/SheetJSAzure` and download
2022-08-21 19:43:30 +00:00
the generated file. Confirm it is a valid file.
6) Deploy to Azure. Replace `NAME_OF_FUNCTION_APP` with the name:
```bash
func azure functionapp publish NAME_OF_FUNCTION_APP
```
2022-08-24 00:51:18 +00:00
Get the function URL and test using the same sequence as in step 5.
2022-08-21 19:43:30 +00:00
</details>
## Azure Blob Storage
The main module for Azure Blob Storage is `@azure/storage-blob`. This example
was tested using the "Connection String" authentication method. The strings
are found in the Azure Portal under "Access Keys" for the storage account.
### Reading Data
The `BlobClient#download` method returns a Stream. After collecting into a
Buffer, `XLSX.read` can parse the data:
```js title="SheetJSReadFromAzure.mjs"
import { BlobServiceClient } from "@azure/storage-blob";
import { read, utils } from "xlsx";
/* replace these constants */
const connStr = "<REPLACE WITH CONNECTION STRING>";
const containerName = "<REPLACE WITH CONTAINER NAME>";
const blobName = "<REPLACE WITH BLOB NAME>";
/* get a readable stream*/
const blobServiceClient = BlobServiceClient.fromConnectionString(connStr);
const containerClient = blobServiceClient.getContainerClient(containerName);
const blobClient = containerClient.getBlobClient(blobName);
const response = (await blobClient.download()).readableStreamBody;
/* collect data into a Buffer */
const bufs = [];
for await(const buf of response) bufs.push(buf);
const downloaded = Buffer.concat(bufs);
/* parse downloaded buffer */
const wb = read(downloaded);
/* print first worksheet */
console.log(utils.sheet_to_csv(wb.Sheets[wb.SheetNames[0]]));
```
### Writing Data
`BlockBlobClient#upload` directly accepts a Buffer:
```js title="SheetJSWriteToAzure.mjs"
import { BlobServiceClient } from "@azure/storage-blob";
2023-04-19 08:50:07 +00:00
import { write, utils } from "xlsx";
2022-08-21 19:43:30 +00:00
/* replace these constants */
const connStr = "<REPLACE WITH CONNECTION STRING>";
const containerName = "<REPLACE WITH CONTAINER NAME>";
const blobName = "<REPLACE WITH BLOB NAME>";
/* Create a simple workbook and write XLSX to buffer */
const ws = utils.aoa_to_sheet(["SheetJS".split(""), [5,4,3,3,7,9,5]]);
const wb = utils.book_new(); utils.book_append_sheet(wb, ws, "Sheet1");
const buf = write(wb, {type: "buffer", bookType: "xlsx"});
/* upload buffer */
const blobServiceClient = BlobServiceClient.fromConnectionString(connStr);
const containerClient = blobServiceClient.getContainerClient(containerName);
const blockBlobClient = containerClient.getBlockBlobClient(blobName);
const uploadBlobResponse = await blockBlobClient.upload(buf, buf.length);
```