forked from sheetjs/docs.sheetjs.com
		
	azure
This commit is contained in:
		
							parent
							
								
									62641b5da6
								
							
						
					
					
						commit
						990f42934b
					
				@ -25,7 +25,7 @@ This demo was verified by NetSuite consultants in the following deployments:
 | 
			
		||||
| `@NScriptType`  | `@NApiVersion` | Date       |
 | 
			
		||||
|:----------------|:---------------|:-----------|
 | 
			
		||||
| ScheduledScript | 2.1            | 2023-08-18 |
 | 
			
		||||
| Restlet         | 2.1            | 2023-04-20 |
 | 
			
		||||
| Restlet         | 2.1            | 2023-10-05 |
 | 
			
		||||
| Suitelet        | 2.1            | 2023-07-21 |
 | 
			
		||||
| MapReduceScript | 2.1            | 2023-07-31 |
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -311,7 +311,7 @@ Function properties.
 | 
			
		||||
 | 
			
		||||
17) Select the "Configuration" tab and select "Permissions" in the left sidebar.
 | 
			
		||||
 | 
			
		||||
18) Scroll down to "Resource-based policy statements" and ensure that 
 | 
			
		||||
18) Scroll down to "Resource-based policy statements" and ensure that
 | 
			
		||||
`FunctionURLAllowPublicAccess` is listed.
 | 
			
		||||
 | 
			
		||||
If no policy statements are defined, select "Add Permission" with the options:
 | 
			
		||||
@ -373,7 +373,7 @@ var s3 = new AWS.S3({
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Reading Data
 | 
			
		||||
### Downloading Data
 | 
			
		||||
 | 
			
		||||
#### Fetching Files from S3
 | 
			
		||||
 | 
			
		||||
@ -425,7 +425,7 @@ stream.on('end', function() {
 | 
			
		||||
});
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Writing Data
 | 
			
		||||
### Uploading Data
 | 
			
		||||
 | 
			
		||||
The SheetJS `write` method[^13] with the option `type: "buffer"` will generate
 | 
			
		||||
NodeJS Buffers. `S3#upload` directly accepts these Buffer objects.
 | 
			
		||||
 | 
			
		||||
@ -5,10 +5,26 @@ pagination_next: demos/extensions/index
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
import current from '/version.js';
 | 
			
		||||
import Tabs from '@theme/Tabs';
 | 
			
		||||
import TabItem from '@theme/TabItem';
 | 
			
		||||
import CodeBlock from '@theme/CodeBlock';
 | 
			
		||||
 | 
			
		||||
Azure is a Cloud Services platform which includes traditional virtual machine
 | 
			
		||||
support, "Serverless Functions", cloud storage and much more.
 | 
			
		||||
[Azure Cloud Services](https://azure.microsoft.com/) is a Cloud Services
 | 
			
		||||
platform which includes traditional virtual machine support, "Serverless
 | 
			
		||||
Functions" and cloud storage.
 | 
			
		||||
 | 
			
		||||
[SheetJS](https://sheetjs.com) is a JavaScript library for reading and writing
 | 
			
		||||
data from spreadsheets.
 | 
			
		||||
 | 
			
		||||
This demo explores two key AWS offerings:
 | 
			
		||||
 | 
			
		||||
- ["Azure Functions"](#azure-functions) ("Lambda") explores the serverless
 | 
			
		||||
  computing offering. The demo creates a JavaScript function that can process
 | 
			
		||||
  user-submitted files and generate spreadsheets.
 | 
			
		||||
 | 
			
		||||
- ["Blob Storage"](#blob-storage) explores the cloud storage offering. The demo
 | 
			
		||||
  uses the NodeJS connection library to read spreadsheets from storage and write
 | 
			
		||||
  spreadsheets back to cloud storage.
 | 
			
		||||
 | 
			
		||||
:::caution pass
 | 
			
		||||
 | 
			
		||||
@ -17,22 +33,77 @@ 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").
 | 
			
		||||
 | 
			
		||||
:::note
 | 
			
		||||
 | 
			
		||||
This demo was last tested on 2023 April 29.
 | 
			
		||||
This demo was last tested on 2023 October 06.
 | 
			
		||||
 | 
			
		||||
:::
 | 
			
		||||
 | 
			
		||||
## Telemetry
 | 
			
		||||
 | 
			
		||||
:::warning Telemetry
 | 
			
		||||
 | 
			
		||||
**Each command-line tool related to Azure embeds telemetry.**
 | 
			
		||||
 | 
			
		||||
Azure tools embed telemetry without proper disclaimer.
 | 
			
		||||
 | 
			
		||||
:::
 | 
			
		||||
 | 
			
		||||
It is strongly recommended to disable telemetry before working with Azure.
 | 
			
		||||
 | 
			
		||||
#### Azure Functions Core Tools
 | 
			
		||||
 | 
			
		||||
Azure Functions Core Tools (`func`) telemetry is controlled through the
 | 
			
		||||
`FUNCTIONS_CORE_TOOLS_TELEMETRY_OPTOUT` environment variable.
 | 
			
		||||
 | 
			
		||||
<Tabs groupId="os">
 | 
			
		||||
  <TabItem value="unix" label="Linux/MacOS">
 | 
			
		||||
 | 
			
		||||
Add the following line to `.profile`, `.bashrc` and `.zshrc`:
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
export FUNCTIONS_CORE_TOOLS_TELEMETRY_OPTOUT=1
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Close and restart the Terminal to load the changes.
 | 
			
		||||
 | 
			
		||||
  </TabItem>
 | 
			
		||||
  <TabItem value="win" label="Windows">
 | 
			
		||||
 | 
			
		||||
Type `env` in the search bar and select "Edit the system environment variables".
 | 
			
		||||
 | 
			
		||||
In the new window, click the "Environment Variables..." button.
 | 
			
		||||
 | 
			
		||||
In the new window, look for the "System variables" section and click "New..."
 | 
			
		||||
 | 
			
		||||
Set the "Variable name" to `FUNCTIONS_CORE_TOOLS_TELEMETRY_OPTOUT` and the value
 | 
			
		||||
to `1`.
 | 
			
		||||
 | 
			
		||||
Click "OK" in each window (3 windows) and restart your computer.
 | 
			
		||||
 | 
			
		||||
  </TabItem>
 | 
			
		||||
</Tabs>
 | 
			
		||||
 | 
			
		||||
#### Azure CLI
 | 
			
		||||
 | 
			
		||||
Azure CLI (`az`) telemetry can be disabled using a subcommand (after installing
 | 
			
		||||
the CLI tool)[^1]:
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
az configure -d collect_telemetry=false
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## Azure Functions
 | 
			
		||||
 | 
			
		||||
The [SheetJS NodeJS module](/docs/getting-started/installation/nodejs) can be
 | 
			
		||||
required in Azure Functions that use the NodeJS runtime.
 | 
			
		||||
 | 
			
		||||
This discussion focuses on the "HTTP Trigger" function type.
 | 
			
		||||
 | 
			
		||||
:::info pass
 | 
			
		||||
:::note pass
 | 
			
		||||
 | 
			
		||||
To enable binary data processing, a setting must be changed in `function.json`:
 | 
			
		||||
In earlier tests, to enable binary data processing, `function.json` required a
 | 
			
		||||
`dataType` option:
 | 
			
		||||
 | 
			
		||||
```json title="function.json"
 | 
			
		||||
{
 | 
			
		||||
@ -45,150 +116,295 @@ To enable binary data processing, a setting must be changed in `function.json`:
 | 
			
		||||
      "name": "req",
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
In the most recent test, the template did not create a `function.json` and the
 | 
			
		||||
option was not required.
 | 
			
		||||
 | 
			
		||||
:::
 | 
			
		||||
 | 
			
		||||
### Reading Data
 | 
			
		||||
 | 
			
		||||
`formidable` expects a stream and Azure does not present one.  It can be made:
 | 
			
		||||
Using `@azure/functions`, the handler callback receives a `Request` object. With
 | 
			
		||||
standard JS operations, the file can be pulled into an `ArrayBuffer` object.
 | 
			
		||||
 | 
			
		||||
The SheetJS `read` method[^2] can read the `ArrayBuffer` objects and generate
 | 
			
		||||
SheetJS workbook objects[^3] which can be processed with other API functions.
 | 
			
		||||
 | 
			
		||||
For example, a handler can use `sheet_to_csv`[^4] to generate CSV text:
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
const { Blob } = require('buffer');
 | 
			
		||||
const { app } = require('@azure/functions');
 | 
			
		||||
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;
 | 
			
		||||
};
 | 
			
		||||
app.http('SheetJSAzure', {
 | 
			
		||||
  methods: ['POST'],
 | 
			
		||||
  handler: async (req, context) => {
 | 
			
		||||
    /* grab the file at form key `upload` */
 | 
			
		||||
    const formData = await req.formData();
 | 
			
		||||
    const f = formData.get("upload");
 | 
			
		||||
 | 
			
		||||
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"});
 | 
			
		||||
    if(!(f instanceof Blob)) return { status: 400, body: "Must submit a 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();
 | 
			
		||||
  });
 | 
			
		||||
}
 | 
			
		||||
    /* parse file */
 | 
			
		||||
    const ab = await f.arrayBuffer();
 | 
			
		||||
    const wb = XLSX.read(ab);
 | 
			
		||||
 | 
			
		||||
    /* generate CSV from first sheet */
 | 
			
		||||
    const ws = wb.Sheets[wb.SheetNames[0]];
 | 
			
		||||
    const csv = XLSX.utils.sheet_to_csv(ws);
 | 
			
		||||
    return { status: 200, body: csv };
 | 
			
		||||
  }
 | 
			
		||||
});
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Writing Data
 | 
			
		||||
 | 
			
		||||
The `body` property can be a Buffer, like those generated by `XLSX.write`:
 | 
			
		||||
The SheetJS `write` method[^5] with the option `type: "buffer"` will generate
 | 
			
		||||
NodeJS buffers which can be sent in the callback handler response.
 | 
			
		||||
 | 
			
		||||
The following example generates a sample worksheet using the `aoa_to_sheet`[^6]
 | 
			
		||||
method, generates a sample workbook using worksheet helper methods[^7], writes
 | 
			
		||||
the workbook to XLSX format in a Buffer, and sends the Buffer in the response:
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
const { app } = require('@azure/functions');
 | 
			
		||||
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();
 | 
			
		||||
};
 | 
			
		||||
app.http('SheetJSAzure', {
 | 
			
		||||
  methods: ['GET'],
 | 
			
		||||
  handler: async (req, context) => {
 | 
			
		||||
    /* generate sample worksheet */
 | 
			
		||||
    var ws = XLSX.utils.aoa_to_sheet(["SheetJS".split(""), [5, 4, 3, 3, 7, 9, 5]]);
 | 
			
		||||
    /* generate workbook */
 | 
			
		||||
    var wb = XLSX.utils.book_new(); XLSX.utils.book_append_sheet(wb, ws, "Data");
 | 
			
		||||
    /* write to XLSX, returning a NodeJS Buffer */
 | 
			
		||||
    var buf = XLSX.write(wb, { type: "buffer", bookType: "xlsx" });
 | 
			
		||||
    /* send Buffer to client */
 | 
			
		||||
    return {
 | 
			
		||||
      status: 200,
 | 
			
		||||
      /* Content-Disposition header */
 | 
			
		||||
      headers: { "Content-Disposition": `attachment; filename="SheetJSAzure.xlsx";` },
 | 
			
		||||
      /* data */
 | 
			
		||||
      body: buf
 | 
			
		||||
    };
 | 
			
		||||
  }
 | 
			
		||||
});
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Demo
 | 
			
		||||
### Functions Demo
 | 
			
		||||
 | 
			
		||||
<details open><summary><b>Complete Example</b> (click to show)</summary>
 | 
			
		||||
:::note pass
 | 
			
		||||
 | 
			
		||||
0) Review the quick start for JavaScript on Azure Functions.  This involves
 | 
			
		||||
installing the Azure Functions Core Tools and other dependencies.
 | 
			
		||||
At the time of writing, the Azure Free Tier included an allowance of 1 million
 | 
			
		||||
free requests per month.
 | 
			
		||||
 | 
			
		||||
1) Create a new project and install dependencies:
 | 
			
		||||
:::
 | 
			
		||||
 | 
			
		||||
0) If you do not have an account, create a new Azure free tier account[^8].
 | 
			
		||||
 | 
			
		||||
#### Local Setup
 | 
			
		||||
 | 
			
		||||
1) [Disable Azure Functions Core Tools Telemetry](#azure-functions-core-tools).
 | 
			
		||||
 | 
			
		||||
2) Install the CLI tool using npm:
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
npm i -g azure-functions-core-tools@4 --unsafe-perm true
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
:::note pass
 | 
			
		||||
 | 
			
		||||
On macOS and Linux, `sudo` may be required:
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
sudo npm i -g azure-functions-core-tools@4 --unsafe-perm true
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
:::
 | 
			
		||||
 | 
			
		||||
3) Install [Azure CLI](https://learn.microsoft.com/en-us/cli/azure/install-azure-cli)
 | 
			
		||||
 | 
			
		||||
4) Disable Azure CLI telemetry:
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
az configure -d collect_telemetry=false
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
#### Start Project
 | 
			
		||||
 | 
			
		||||
5) Create a new JavaScript HTTP Trigger project:
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
mkdir SheetJSAzure
 | 
			
		||||
cd SheetJSAzure
 | 
			
		||||
func new --template httpTrigger --language JavaScript --name SheetJSAzure
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
:::warning pass
 | 
			
		||||
 | 
			
		||||
When the demo was last tested, the stock TypeScript template did not work.
 | 
			
		||||
 | 
			
		||||
**This is a bug in the Azure Functions Core Tools**
 | 
			
		||||
 | 
			
		||||
Until the bugs are resolved, JavaScript should be preferred over TypeScript.
 | 
			
		||||
 | 
			
		||||
:::
 | 
			
		||||
 | 
			
		||||
6) Start the local server:
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
npm start
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
7) While the server is running, open a new terminal window and make a request:
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
curl -L http://localhost:7071/api/SheetJSAzure
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
The terminal should display `Hello, world!`
 | 
			
		||||
 | 
			
		||||
#### Add SheetJS
 | 
			
		||||
 | 
			
		||||
8) Install the SheetJS NodeJS module:
 | 
			
		||||
 | 
			
		||||
<CodeBlock language="bash">{`\
 | 
			
		||||
func init sheetjs-azure --worker-runtime node --language javascript
 | 
			
		||||
cd sheetjs-azure
 | 
			
		||||
npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz formidable`}
 | 
			
		||||
npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz`}
 | 
			
		||||
</CodeBlock>
 | 
			
		||||
 | 
			
		||||
2) Create a new "HTTP Trigger" function:
 | 
			
		||||
9) Download [the sample script](pathname:///azure/index.js):
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
func new --template "Http Trigger" --name SheetJSAzure
 | 
			
		||||
curl -L -o src/functions/SheetJSAzure.js https://docs.sheetjs.com/azure/index.js
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
3) Edit `SheetJSAzure/function.json` to add the `dataType: "binary"` property:
 | 
			
		||||
#### Local Test
 | 
			
		||||
 | 
			
		||||
```js title="SheetJSAzure/function.json"
 | 
			
		||||
      "direction": "in",
 | 
			
		||||
// highlight-next-line
 | 
			
		||||
      "dataType": "binary",
 | 
			
		||||
      "name": "req",
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
4) Download [`SheetJSAzure/index.js`](pathname:///aws/index.js):
 | 
			
		||||
10) Stop and restart the dev server:
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
curl -L -o SheetJSAzure/index.js https://docs.sheetjs.com/azure/index.js
 | 
			
		||||
npm start
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
5) Test locally with `npm start`
 | 
			
		||||
 | 
			
		||||
To test uploads, download <https://sheetjs.com/pres.numbers> and run:
 | 
			
		||||
11) In a separate terminal window, download <https://sheetjs.com/pres.numbers>
 | 
			
		||||
and make a POST request to the dev server:
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
curl -LO https://sheetjs.com/pres.numbers
 | 
			
		||||
curl -X POST -F "upload=@pres.numbers" http://localhost:7071/api/SheetJSAzure
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
To test downloads, access `http://localhost:7071/api/SheetJSAzure` and download
 | 
			
		||||
the generated file.  Confirm it is a valid file.
 | 
			
		||||
If the test succeeded, the terminal will print CSV rows from the test file data.
 | 
			
		||||
 | 
			
		||||
6) Deploy to Azure.  Replace `NAME_OF_FUNCTION_APP` with the name:
 | 
			
		||||
12) Open a web browser and access `http://localhost:7071/api/SheetJSAzure` .
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
func azure functionapp publish NAME_OF_FUNCTION_APP
 | 
			
		||||
If the test succeeded, the browser will attempt to download `SheetJSAzure.xlsx`.
 | 
			
		||||
Open in Excel or another spreadsheet editor to confirm the file is valid.
 | 
			
		||||
 | 
			
		||||
#### Create Remote Function
 | 
			
		||||
 | 
			
		||||
13) Sign into the [Azure Portal](https://portal.azure.com/#home)
 | 
			
		||||
 | 
			
		||||
14) Type "Function App" in the top search box and click "Function App"
 | 
			
		||||
 | 
			
		||||
15) Click "+ Create"
 | 
			
		||||
 | 
			
		||||
16) Select the following options:
 | 
			
		||||
 | 
			
		||||
- Type a memorable "Function Name" ("sheetjsazure" when last tested)
 | 
			
		||||
 | 
			
		||||
- "Do you want to deploy code or container image?": select "Code"
 | 
			
		||||
 | 
			
		||||
- "Runtime stack": select NodeJS
 | 
			
		||||
 | 
			
		||||
- "Hosting options and plans": "Consumption (Serverless)"
 | 
			
		||||
 | 
			
		||||
17) Click "Review + create", then click "Create" to create the function.
 | 
			
		||||
 | 
			
		||||
The page will display a status message
 | 
			
		||||
 | 
			
		||||
> ... Deployment is in progress
 | 
			
		||||
 | 
			
		||||
When the resources are configured, the status will change to
 | 
			
		||||
 | 
			
		||||
> Your deployment is complete
 | 
			
		||||
 | 
			
		||||
18) Click "Go to Resource".
 | 
			
		||||
 | 
			
		||||
19) Take note of the URL from the table
 | 
			
		||||
 | 
			
		||||
#### Deploy to Azure
 | 
			
		||||
 | 
			
		||||
20) Sign into Azure:
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
az login
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Get the function URL and test using the same sequence as in step 5.
 | 
			
		||||
The login flow resumes in the browser.
 | 
			
		||||
 | 
			
		||||
</details>
 | 
			
		||||
21) Deploy to Azure.  Replace `FUNCTION_NAME` with the name from Step 16:
 | 
			
		||||
 | 
			
		||||
## Azure Blob Storage
 | 
			
		||||
```bash
 | 
			
		||||
func azure functionapp publish FUNCTION_NAME
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
After publishing, the process will print the "Invoke url":
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
Functions in sheetjsazure:
 | 
			
		||||
    SheetJSAzure - [httpTrigger]
 | 
			
		||||
// highlight-next-line
 | 
			
		||||
        Invoke url: https://sheetjsazure.azurewebsites.net/api/sheetjsazure
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Take note of that URL.
 | 
			
		||||
 | 
			
		||||
#### Remote Test
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
22) In a separate terminal window, download <https://sheetjs.com/pres.numbers>
 | 
			
		||||
and make a POST request to the production server. Replace `FUNCTION_URL` with
 | 
			
		||||
the Invoke URL from Step 21:
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
curl -LO https://sheetjs.com/pres.numbers
 | 
			
		||||
curl -X POST -F "upload=@pres.numbers" FUNCTION_URL
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
If the test succeeded, the terminal will print CSV rows from the test file data.
 | 
			
		||||
 | 
			
		||||
23) Open a web browser and access the Invoke URL from Step 21.
 | 
			
		||||
 | 
			
		||||
If the test succeeded, the browser will attempt to download `SheetJSAzure.xlsx`.
 | 
			
		||||
Open in Excel or another spreadsheet editor to confirm the file is valid.
 | 
			
		||||
 | 
			
		||||
## 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
 | 
			
		||||
### Downloading Data
 | 
			
		||||
 | 
			
		||||
The `BlobClient#download` method returns a Stream. After collecting into a
 | 
			
		||||
Buffer, `XLSX.read` can parse the data:
 | 
			
		||||
Buffer, the SheetJS `read` method[^9] can parse the data into a workbook[^10].
 | 
			
		||||
 | 
			
		||||
The following demo uses the `sheet_to_csv`[^11] utility function to display the
 | 
			
		||||
contents of a file in Azure Blob Storage:
 | 
			
		||||
 | 
			
		||||
```js title="SheetJSReadFromAzure.mjs"
 | 
			
		||||
import { BlobServiceClient } from "@azure/storage-blob";
 | 
			
		||||
import { read, utils } from "xlsx";
 | 
			
		||||
 | 
			
		||||
/* replace these constants */
 | 
			
		||||
// highlight-start
 | 
			
		||||
const connStr = "<REPLACE WITH CONNECTION STRING>";
 | 
			
		||||
const containerName = "<REPLACE WITH CONTAINER NAME>";
 | 
			
		||||
const blobName = "<REPLACE WITH BLOB NAME>";
 | 
			
		||||
// highlight-end
 | 
			
		||||
 | 
			
		||||
/* Blob name */
 | 
			
		||||
const blobName = "SheetJSBloblobber.xlsx";
 | 
			
		||||
 | 
			
		||||
/* get a readable stream*/
 | 
			
		||||
const blobServiceClient = BlobServiceClient.fromConnectionString(connStr);
 | 
			
		||||
@ -207,18 +423,27 @@ const wb = read(downloaded);
 | 
			
		||||
console.log(utils.sheet_to_csv(wb.Sheets[wb.SheetNames[0]]));
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Writing Data
 | 
			
		||||
### Uploading Data
 | 
			
		||||
 | 
			
		||||
`BlockBlobClient#upload` directly accepts a Buffer:
 | 
			
		||||
The SheetJS `write` method[^12] with the option `type: "buffer"` will generate
 | 
			
		||||
NodeJS buffers which can be uploaded with `BlockBlobClient#upload`.
 | 
			
		||||
 | 
			
		||||
The following example generates a sample worksheet using the `aoa_to_sheet`[^13]
 | 
			
		||||
method, generates a sample workbook using worksheet helper methods[^14], writes
 | 
			
		||||
the workbook to XLSX format in a Buffer, and sends the Buffer in the response:
 | 
			
		||||
 | 
			
		||||
```js title="SheetJSWriteToAzure.mjs"
 | 
			
		||||
import { BlobServiceClient } from "@azure/storage-blob";
 | 
			
		||||
import { write, utils } from "xlsx";
 | 
			
		||||
 | 
			
		||||
/* replace these constants */
 | 
			
		||||
// highlight-start
 | 
			
		||||
const connStr = "<REPLACE WITH CONNECTION STRING>";
 | 
			
		||||
const containerName = "<REPLACE WITH CONTAINER NAME>";
 | 
			
		||||
const blobName = "<REPLACE WITH BLOB NAME>";
 | 
			
		||||
// highlight-end
 | 
			
		||||
 | 
			
		||||
/* Blob name */
 | 
			
		||||
const blobName = "SheetJSBloblobber.xlsx";
 | 
			
		||||
 | 
			
		||||
/* Create a simple workbook and write XLSX to buffer */
 | 
			
		||||
const ws = utils.aoa_to_sheet(["SheetJS".split(""), [5,4,3,3,7,9,5]]);
 | 
			
		||||
@ -231,3 +456,165 @@ const containerClient = blobServiceClient.getContainerClient(containerName);
 | 
			
		||||
const blockBlobClient = containerClient.getBlockBlobClient(blobName);
 | 
			
		||||
const uploadBlobResponse = await blockBlobClient.upload(buf, buf.length);
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Blob Demo
 | 
			
		||||
 | 
			
		||||
:::note pass
 | 
			
		||||
 | 
			
		||||
At the time of writing, new Azure accounts were granted a 12-month trial of Blob
 | 
			
		||||
Storage. The trial includes 5GB of "Locally-redundant storage" with 20,000 read
 | 
			
		||||
requests and 2000 write requests per month.
 | 
			
		||||
 | 
			
		||||
:::
 | 
			
		||||
 | 
			
		||||
0) If you do not have an account, create a new Azure free tier account[^8].
 | 
			
		||||
 | 
			
		||||
#### Storage Account Setup
 | 
			
		||||
 | 
			
		||||
1) Sign into the [Azure Portal](https://portal.azure.com/#home)
 | 
			
		||||
 | 
			
		||||
2) Type "Storage" in the top search box and click "Storage accounts"
 | 
			
		||||
 | 
			
		||||
3) Click "+ Create"
 | 
			
		||||
 | 
			
		||||
4) Select the following options:
 | 
			
		||||
 | 
			
		||||
- Type a memorable "Storage account name" ("sheetjstorage" when last tested)
 | 
			
		||||
 | 
			
		||||
- "Redundancy": select LRS (Locally-redundant storage)
 | 
			
		||||
 | 
			
		||||
- "Hosting options and plans": "Consumption (Serverless)"
 | 
			
		||||
 | 
			
		||||
5) Click "Review", then click "Create" to create the storage.
 | 
			
		||||
 | 
			
		||||
The page will display a status message
 | 
			
		||||
 | 
			
		||||
> ... Deployment is in progress
 | 
			
		||||
 | 
			
		||||
When the resources are configured, the status will change to
 | 
			
		||||
 | 
			
		||||
> Your deployment is complete
 | 
			
		||||
 | 
			
		||||
6) Click "Go to Resource".
 | 
			
		||||
 | 
			
		||||
#### Access Keys
 | 
			
		||||
 | 
			
		||||
7) Click "Access keys" in the left sidebar (under "Security + networking")
 | 
			
		||||
 | 
			
		||||
8) Look for the "Connection string" title under "key1". In the row below the
 | 
			
		||||
title, click "Show" to reveal the key. Click the copy icon or manually copy the
 | 
			
		||||
key, storing it in a safe place.
 | 
			
		||||
 | 
			
		||||
#### Container Setup
 | 
			
		||||
 | 
			
		||||
9) Click "Containers" in the left sidebar.
 | 
			
		||||
 | 
			
		||||
10) Click "+ Container"
 | 
			
		||||
 | 
			
		||||
11) Select the following options:
 | 
			
		||||
 | 
			
		||||
- Type a memorable "Name" ("sheetjs-container" when last tested)
 | 
			
		||||
 | 
			
		||||
12) Click "Create" to create the container.
 | 
			
		||||
 | 
			
		||||
#### Project Setup
 | 
			
		||||
 | 
			
		||||
13) Create a new project folder:
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
mkdir SheetJSBlob
 | 
			
		||||
cd SheetJSBlob
 | 
			
		||||
npm init -y
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
14) Install dependencies:
 | 
			
		||||
 | 
			
		||||
<CodeBlock language="bash">{`\
 | 
			
		||||
npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz @azure/storage-blob`}
 | 
			
		||||
</CodeBlock>
 | 
			
		||||
 | 
			
		||||
14) Copy the [`SheetJSReadFromAzure.mjs` code block](#downloading-data) and save
 | 
			
		||||
to `SheetJSReadFromAzure.mjs`.
 | 
			
		||||
 | 
			
		||||
15) Copy the [`SheetJSWriteToAzure.mjs` code block](#uploading-data) and save
 | 
			
		||||
to `SheetJSWriteToAzure.mjs`.
 | 
			
		||||
 | 
			
		||||
16) Edit both `SheetJSReadFromAzure.mjs` and `SheetJSWriteToAzure.mjs`:
 | 
			
		||||
 | 
			
		||||
- Replace the `connStr` value with the connection string from Step 8
 | 
			
		||||
- Replace the `containerName` value with the container name from Step 11
 | 
			
		||||
 | 
			
		||||
#### Test
 | 
			
		||||
 | 
			
		||||
:::note pass
 | 
			
		||||
 | 
			
		||||
The write demo creates a simple workbook, generates a NodeJS buffer, and uploads
 | 
			
		||||
the buffer to a file named `SheetJSBloblobber.xlsx` on Azure Blob Storage.
 | 
			
		||||
 | 
			
		||||
The read demo fetches `SheetJSBloblobber.xlsx` and displays the data.
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
   | A | B | C | D | E | F | G |
 | 
			
		||||
---+---|---|---|---|---|---|---|
 | 
			
		||||
 1 | S | h | e | e | t | J | S |
 | 
			
		||||
 2 | 5 | 4 | 3 | 3 | 7 | 9 | 5 |
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
:::
 | 
			
		||||
 | 
			
		||||
17) Run the write test:
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
node SheetJSWriteToAzure.mjs
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
This will write the file `SheetJSBloblobber.xlsx` to the container.
 | 
			
		||||
 | 
			
		||||
18) Run the read test:
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
node SheetJSReadFromAzure.mjs
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
It will fetch the file created in the previous step and display CSV rows.
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
S,h,e,e,t,J,S
 | 
			
		||||
5,4,3,3,7,9,5
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
19) Sign into the [Azure Portal](https://portal.azure.com/#home)
 | 
			
		||||
 | 
			
		||||
20) Type "Storage" in the top search box and click "Storage accounts"
 | 
			
		||||
 | 
			
		||||
21) Click on the name of the storage
 | 
			
		||||
 | 
			
		||||
22) In the middle column, click "Containers". It will be under "Data storage".
 | 
			
		||||
 | 
			
		||||
23) Click on the name of the container in the table
 | 
			
		||||
 | 
			
		||||
24) Verify that the table shows `SheetJSBloblobber.xlsx`:
 | 
			
		||||
 | 
			
		||||

 | 
			
		||||
 | 
			
		||||
25) Click on the name `SheetJSBloblobber.xlsx`.
 | 
			
		||||
 | 
			
		||||
26) In the right pane, click "Download".
 | 
			
		||||
 | 
			
		||||
The downloaded file is the raw file stored in Azure Blob Storage. To confirm it
 | 
			
		||||
is valid, open the file in Excel or another spreadsheet editor.
 | 
			
		||||
 | 
			
		||||
[^1]: The platform-specific installers are available at <https://learn.microsoft.com/en-us/cli/azure/install-azure-cli>
 | 
			
		||||
[^2]: See [`read` in "Reading Files"](/docs/api/parse-options)
 | 
			
		||||
[^3]: See ["Workbook Object" in "SheetJS Data Model"](/docs/csf/book) for more details.
 | 
			
		||||
[^4]: See [`sheet_to_csv` in "CSV and Text"](/docs/api/utilities/csv#delimiter-separated-output)
 | 
			
		||||
[^5]: See [`write` in "Writing Files"](/docs/api/write-options)
 | 
			
		||||
[^6]: See [`aoa_to_sheet` in "Utilities"](/docs/api/utilities/array#array-of-arrays-input)
 | 
			
		||||
[^7]: See ["Workbook Helpers" in "Utilities"](/docs/api/utilities/wb) for details on `book_new` and `book_append_sheet`.
 | 
			
		||||
[^8]: Registering for a free account [on the Azure Free Tier](https://azure.microsoft.com/en-us/free) requires a valid phone number and a valid credit card.
 | 
			
		||||
[^9]: See [`read` in "Reading Files"](/docs/api/parse-options)
 | 
			
		||||
[^10]: See ["Workbook Object" in "SheetJS Data Model"](/docs/csf/book) for more details.
 | 
			
		||||
[^11]: See [`sheet_to_csv` in "CSV and Text"](/docs/api/utilities/csv#delimiter-separated-output)
 | 
			
		||||
[^12]: See [`write` in "Writing Files"](/docs/api/write-options)
 | 
			
		||||
[^13]: See [`aoa_to_sheet` in "Utilities"](/docs/api/utilities/array#array-of-arrays-input)
 | 
			
		||||
[^14]: See ["Workbook Helpers" in "Utilities"](/docs/api/utilities/wb) for details on `book_new` and `book_append_sheet`.
 | 
			
		||||
 | 
			
		||||
@ -5,6 +5,8 @@ title: Overview
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
import current from '/version.js';
 | 
			
		||||
import Tabs from '@theme/Tabs';
 | 
			
		||||
import TabItem from '@theme/TabItem';
 | 
			
		||||
import CodeBlock from '@theme/CodeBlock';
 | 
			
		||||
 | 
			
		||||
# SheetJS CE
 | 
			
		||||
@ -27,6 +29,9 @@ run entirely in the web browser.
 | 
			
		||||
 | 
			
		||||
<details><summary><b>How to add to your site</b> (click to show)</summary>
 | 
			
		||||
 | 
			
		||||
<Tabs groupId="deployment">
 | 
			
		||||
  <TabItem value="vanilla" label="HTML">
 | 
			
		||||
 | 
			
		||||
1) Make sure your table has an ID:
 | 
			
		||||
 | 
			
		||||
```html
 | 
			
		||||
@ -45,7 +50,7 @@ run entirely in the web browser.
 | 
			
		||||
<button id="sheetjsexport"><b>Export as XLSX</b></button>
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
4) Add an event handler for the `click` event to create a workbook and download:
 | 
			
		||||
4) Add an event handler for the `click` event to export table data to XLSX:
 | 
			
		||||
 | 
			
		||||
```html
 | 
			
		||||
<script>
 | 
			
		||||
@ -58,6 +63,117 @@ document.getElementById("sheetjsexport").addEventListener('click', function() {
 | 
			
		||||
</script>
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
  </TabItem>
 | 
			
		||||
  <TabItem value="react" label="React">
 | 
			
		||||
 | 
			
		||||
:::note pass
 | 
			
		||||
 | 
			
		||||
This example assumes you have an existing project with an HTML TABLE element:
 | 
			
		||||
 | 
			
		||||
```jsx title="Sample Component"
 | 
			
		||||
function App() {
 | 
			
		||||
  return ( <>
 | 
			
		||||
      <h3>SheetJS Table</h3>
 | 
			
		||||
      <table>
 | 
			
		||||
        <tr><td colSpan="3">SheetJS Table Export</td></tr>
 | 
			
		||||
        <tr><td>Author</td><td>ID</td><td>你好!</td></tr>
 | 
			
		||||
        <tr><td>SheetJS</td><td>7262</td><td>வணக்கம்!</td></tr>
 | 
			
		||||
        <tr><td colSpan="3">
 | 
			
		||||
          <a href="//sheetjs.com">Powered by SheetJS</a>
 | 
			
		||||
        </td></tr>
 | 
			
		||||
      </table>
 | 
			
		||||
  </> )
 | 
			
		||||
}
 | 
			
		||||
export default App;
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
If you are starting from scratch, create a new ViteJS + ReactJS project:
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
npm create vite@latest -- sheetjs-react --template react --default
 | 
			
		||||
cd sheetjs-react
 | 
			
		||||
npm install
 | 
			
		||||
npm run dev
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Replace `src/App.jsx` with the sample component.
 | 
			
		||||
 | 
			
		||||
:::
 | 
			
		||||
 | 
			
		||||
1) Install the SheetJS library using a package manager:
 | 
			
		||||
 | 
			
		||||
<Tabs groupId="pm">
 | 
			
		||||
  <TabItem value="npm" label="npm">
 | 
			
		||||
<CodeBlock language="bash">{`\
 | 
			
		||||
npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz`}
 | 
			
		||||
</CodeBlock>
 | 
			
		||||
  </TabItem>
 | 
			
		||||
  <TabItem value="pnpm" label="pnpm">
 | 
			
		||||
<CodeBlock language="bash">{`\
 | 
			
		||||
pnpm install https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz`}
 | 
			
		||||
</CodeBlock>
 | 
			
		||||
  </TabItem>
 | 
			
		||||
  <TabItem value="yarn" label="Yarn" default>
 | 
			
		||||
<CodeBlock language="bash">{`\
 | 
			
		||||
yarn add https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz`}
 | 
			
		||||
</CodeBlock>
 | 
			
		||||
  </TabItem>
 | 
			
		||||
</Tabs>
 | 
			
		||||
 | 
			
		||||
2) Ensure that your component script imports `useRef` from the `react` library:
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
import { useRef } from "react";
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
3) Add the following line at the top of your component script:
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
import { utils, writeFileXLSX } from "xlsx";
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
4) Create a ref in the body of your function component:
 | 
			
		||||
 | 
			
		||||
```jsx
 | 
			
		||||
function App() {
 | 
			
		||||
// highlight-next-line
 | 
			
		||||
  const tbl = useRef(null);
 | 
			
		||||
  // ...
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
5) Attach the ref to the table element:
 | 
			
		||||
 | 
			
		||||
```jsx
 | 
			
		||||
function App() {
 | 
			
		||||
  // ...
 | 
			
		||||
  return (
 | 
			
		||||
    {/*...*/}
 | 
			
		||||
// highlight-next-line
 | 
			
		||||
    <table ref={tbl}>
 | 
			
		||||
      {/*...*/}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
6) Add a button with a click handler that will export table data to XLSX:
 | 
			
		||||
 | 
			
		||||
```jsx
 | 
			
		||||
function App() {
 | 
			
		||||
  // ...
 | 
			
		||||
  return (
 | 
			
		||||
    {/*...*/}
 | 
			
		||||
// highlight-start
 | 
			
		||||
    <button onClick={() => {
 | 
			
		||||
      // generate workbook from table element
 | 
			
		||||
      const wb = utils.table_to_book(tbl.current);
 | 
			
		||||
      // write to XLSX
 | 
			
		||||
      writeFileXLSX(wb, "SheetJSReactExport.xlsx");
 | 
			
		||||
    }}>Export XLSX</button>
 | 
			
		||||
// highlight-end
 | 
			
		||||
    {/*...*/}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
  </TabItem>
 | 
			
		||||
</Tabs>
 | 
			
		||||
 | 
			
		||||
</details>
 | 
			
		||||
 | 
			
		||||
<details><summary><b>How to automate with NodeJS</b> (click to show)</summary>
 | 
			
		||||
@ -74,7 +190,7 @@ using the `puppeteer` and `playwright` browser automation frameworks.
 | 
			
		||||
function Table2XLSX(props) {
 | 
			
		||||
 | 
			
		||||
  /* Callback invoked when the button is clicked */
 | 
			
		||||
  const xport = React.useCallback(async () => {
 | 
			
		||||
  const xport = React.useCallback(() => {
 | 
			
		||||
    /* Create worksheet from HTML DOM TABLE */
 | 
			
		||||
    const table = document.getElementById("Table2XLSX");
 | 
			
		||||
    const wb = XLSX.utils.table_to_book(table);
 | 
			
		||||
 | 
			
		||||
@ -202,6 +202,7 @@ const config = {
 | 
			
		||||
        { from: '/docs/demos/hosting/dropbox', to: '/docs/demos/cloud/dropbox/' },
 | 
			
		||||
        { from: '/docs/demos/hosting/github', to: '/docs/demos/cloud/github/' },
 | 
			
		||||
        /* data */
 | 
			
		||||
        { from: '/docs/getting-started/demos/database', to: '/docs/demos/data/' },
 | 
			
		||||
        { from: '/docs/demos/database', to: '/docs/demos/data/' },
 | 
			
		||||
        { from: '/docs/demos/nosql', to: '/docs/demos/data/' },
 | 
			
		||||
        { from: '/docs/getting-started/demos/nosql', to: '/docs/demos/data/' },
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										
											BIN
										
									
								
								docz/static/azure/bloblobber.png
									
									
									
									
									
										Normal file
									
								
							
							
								
									
								
								
								
								
								
									
									
								
							
						
						
									
										
											BIN
										
									
								
								docz/static/azure/bloblobber.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 25 KiB  | 
@ -1,49 +1,38 @@
 | 
			
		||||
/* sheetjs (C) SheetJS -- https://sheetjs.com */
 | 
			
		||||
const { Blob } = require('buffer');
 | 
			
		||||
const { app } = require('@azure/functions');
 | 
			
		||||
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;
 | 
			
		||||
};
 | 
			
		||||
app.http('SheetJSAzure', {
 | 
			
		||||
  methods: ['GET', 'POST'],
 | 
			
		||||
  authLevel: 'anonymous',
 | 
			
		||||
  handler: async (req, context) => {
 | 
			
		||||
    if (req.method == "POST") {
 | 
			
		||||
      /* grab the file at form key `upload` */
 | 
			
		||||
      const formData = await req.formData();
 | 
			
		||||
      const f = formData.get("upload");
 | 
			
		||||
 | 
			
		||||
module.exports = (context, req) => {
 | 
			
		||||
  if(req.method == "POST") {
 | 
			
		||||
    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!" };
 | 
			
		||||
      if (!f || !(f instanceof Blob)) {
 | 
			
		||||
        return { 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"});
 | 
			
		||||
        /* parse file */
 | 
			
		||||
        const ab = await f.arrayBuffer();
 | 
			
		||||
        const wb = XLSX.read(ab);
 | 
			
		||||
 | 
			
		||||
        /* generate CSV from first sheet */
 | 
			
		||||
        const csv = XLSX.utils.sheet_to_csv(wb.Sheets[wb.SheetNames[0]]);
 | 
			
		||||
        context.res = { status: 200, body: csv };
 | 
			
		||||
        return { status: 200, body: csv };
 | 
			
		||||
      }
 | 
			
		||||
      context.done();
 | 
			
		||||
    });
 | 
			
		||||
  } else if(req.method == "GET") {
 | 
			
		||||
    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");
 | 
			
		||||
    var buf = XLSX.write(wb, {type: "buffer", bookType: "xlsx"});
 | 
			
		||||
    context.res = {
 | 
			
		||||
      status: 200,
 | 
			
		||||
      headers: { "Content-Disposition": `attachment; filename="SheetJSAzure.xlsx";` },
 | 
			
		||||
      body: buf
 | 
			
		||||
    };
 | 
			
		||||
    context.done();
 | 
			
		||||
  } else {
 | 
			
		||||
    context.res = { status: 500, body: `Unsupported method ${req.method}` };
 | 
			
		||||
    context.done();
 | 
			
		||||
 | 
			
		||||
    } else if (req.method == "GET") {
 | 
			
		||||
      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");
 | 
			
		||||
      var buf = XLSX.write(wb, { type: "buffer", bookType: "xlsx" });
 | 
			
		||||
      return {
 | 
			
		||||
        status: 200,
 | 
			
		||||
        headers: { "Content-Disposition": `attachment; filename="SheetJSAzure.xlsx";` },
 | 
			
		||||
        body: buf
 | 
			
		||||
      };
 | 
			
		||||
    } else return { status: 500, body: `Unsupported method ${req.method}` };
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
});
 | 
			
		||||
@ -1,11 +1,11 @@
 | 
			
		||||
/*
 | 
			
		||||
  Licensing Note:
 | 
			
		||||
 | 
			
		||||
  At the time this extract was made (2023 May 28), the linked license page
 | 
			
		||||
  At the time this snapshot was taken, the linked license page
 | 
			
		||||
 | 
			
		||||
    http://www.codeplex.com/ChinookDatabase/license
 | 
			
		||||
 | 
			
		||||
  was unavailable (Microsoft shuttered CodePlex).
 | 
			
		||||
  was unavailable (Microsoft shuttered CodePlex in 2021)
 | 
			
		||||
 | 
			
		||||
  archive.org has a snapshot of the project license page:
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user