From 7e88f2db0b52999bd859f67af4f546911ea6861f Mon Sep 17 00:00:00 2001 From: SheetJS Date: Sun, 19 Nov 2023 21:51:39 -0500 Subject: [PATCH] upload --- .../03-net/01-network/_category_.json | 5 + .../{01-network.mdx => 01-network/index.mdx} | 284 +------- .../03-demos/03-net/02-upload/_category_.json | 5 + docz/docs/03-demos/03-net/02-upload/index.mdx | 608 ++++++++++++++++++ .../{02-server => 03-server}/01-express.md | 2 +- .../{02-server => 03-server}/04-drash.md | 2 +- .../{02-server => 03-server}/09-elysia.md | 2 +- .../{02-server => 03-server}/11-nestjs.md | 2 +- .../{02-server => 03-server}/19-fastify.md | 2 +- .../{02-server => 03-server}/_category_.json | 2 +- .../03-net/{02-server => 03-server}/index.md | 11 +- 11 files changed, 664 insertions(+), 261 deletions(-) create mode 100644 docz/docs/03-demos/03-net/01-network/_category_.json rename docz/docs/03-demos/03-net/{01-network.mdx => 01-network/index.mdx} (63%) create mode 100644 docz/docs/03-demos/03-net/02-upload/_category_.json create mode 100644 docz/docs/03-demos/03-net/02-upload/index.mdx rename docz/docs/03-demos/03-net/{02-server => 03-server}/01-express.md (98%) rename docz/docs/03-demos/03-net/{02-server => 03-server}/04-drash.md (99%) rename docz/docs/03-demos/03-net/{02-server => 03-server}/09-elysia.md (99%) rename docz/docs/03-demos/03-net/{02-server => 03-server}/11-nestjs.md (99%) rename docz/docs/03-demos/03-net/{02-server => 03-server}/19-fastify.md (98%) rename docz/docs/03-demos/03-net/{02-server => 03-server}/_category_.json (78%) rename docz/docs/03-demos/03-net/{02-server => 03-server}/index.md (96%) diff --git a/docz/docs/03-demos/03-net/01-network/_category_.json b/docz/docs/03-demos/03-net/01-network/_category_.json new file mode 100644 index 0000000..93272f9 --- /dev/null +++ b/docz/docs/03-demos/03-net/01-network/_category_.json @@ -0,0 +1,5 @@ +{ + "label": "HTTP Downloads", + "collapsed": false, + "position": 1 +} \ No newline at end of file diff --git a/docz/docs/03-demos/03-net/01-network.mdx b/docz/docs/03-demos/03-net/01-network/index.mdx similarity index 63% rename from docz/docs/03-demos/03-net/01-network.mdx rename to docz/docs/03-demos/03-net/01-network/index.mdx index caf9f7b..562b4b5 100644 --- a/docz/docs/03-demos/03-net/01-network.mdx +++ b/docz/docs/03-demos/03-net/01-network/index.mdx @@ -1,6 +1,6 @@ --- -title: HTTP Network Requests -pagination_next: demos/net/server/index +title: HTTP Downloads +pagination_next: demos/net/upload/index --- @@ -11,6 +11,15 @@ pagination_next: demos/net/server/index import current from '/version.js'; import CodeBlock from '@theme/CodeBlock'; +:::info pass + +This demo focuses on downloading files. Other demos cover other HTTP use cases: + +- ["HTTP Uploads"](/docs/demos/net/upload) covers uploading files +- ["HTTP Server Processing"](/docs/demos/net/server) covers HTTP servers + +::: + `XMLHttpRequest` and `fetch` browser APIs enable binary data transfer between web browser clients and web servers. Since this library works in web browsers, server conversion work can be offloaded to the client! This demo shows a few @@ -18,15 +27,12 @@ common scenarios involving browser APIs and popular wrapper libraries. :::caution Third-Party Hosts and Binary Data -Some services like AWS will corrupt raw binary uploads / downloads by encoding -requests and responses in UTF-8. Typically, these services have options for -disabling this behavior. +Third-party cloud platforms such as AWS may corrupt raw binary downloads by +encoding requests and responses in UTF-8 strings. For AWS, in the "Binary Media Types" section of the API Gateway console, the -following types should be added to ensure smooth uploads and downloads: - -- `"multipart/form-data"` (for Lambda functions to receive files from clients) -- `"application/vnd.ms-excel"` (for Lambda functions to send files to clients) +`"application/vnd.ms-excel"` type should be added to ensure that AWS Lambda +functions functions can send files to clients. ::: @@ -37,51 +43,28 @@ that represent invalid UTF-8 characters. The APIs generally have a way to control the interpretation of the downloaded data. The `arraybuffer` response type usually forces the data to be presented -as a pure `ArrayBuffer` which can be parsed directly with `XLSX.read`. +as an `ArrayBuffer` which can be parsed directly with the SheetJS `read` method[^1]. For example, with `fetch`: ```js +/* download data into an ArrayBuffer object */ const res = await fetch("https://sheetjs.com/pres.numbers"); const ab = await res.arrayBuffer(); // recover data as ArrayBuffer +/* parse file */ const wb = XLSX.read(ab); ``` -## Uploading Binary Data - -`FormData` objects can hold `File` blobs generated from `XLSX.write`: - -```js -/* generate XLSX file bytes */ -var data = XLSX.write(workbook, {bookType: 'xlsx', type: 'array'}); - -/* build FormData with the generated file */ -var fdata = new FormData(); -fdata.append('data', new File([data], 'sheetjs.xlsx')); -// field name ^^^^ file name ^^^^^^^^^^^^ -``` - -The `FormData` object can be passed along to the POST request. For example: - -```js -var req = new XMLHttpRequest(); -req.open("POST", "/upload", true); -req.send(fdata); -``` - ## Browser Demos -The included demos focus on an editable table. There are two separate flows: +The included demos focus on an editable table. -- When the page is accessed, the browser will attempt to download - and read the workbook. The old table will be replaced with an editable table - whose contents match the first worksheet. The table is generated using the - `sheet_to_html` utility with `editable:true` option +When the page is accessed, the browser will attempt to download +and read the workbook. The old table will be replaced with a table whose +contents match the first worksheet. The table is generated using the SheetJS +`sheet_to_html` method[^2] -- When the upload button is clicked, the browser will generate a new worksheet - using `table_to_book` and build up a new workbook. It will then attempt to - generate a file, upload it to and show the response. ### XMLHttpRequest @@ -135,64 +118,6 @@ function SheetJSXHRDL() { -For uploading data, this demo populates a `FormData` object with an ArrayBuffer -generated with the `array` output type: - -```js -/* generate XLSX as array buffer */ -var data = XLSX.write(workbook, {bookType: 'xlsx', type: 'array'}); - -/* build FormData with the generated file */ -var fd = new FormData(); -fd.append('data', new File([data], 'sheetjs.xlsx')); - -/* send data */ -var req = new XMLHttpRequest(); -req.open("POST", url, true); -req.send(fd); -``` - -
Live Upload demo (click to show) - -This demo uses `XMLHttpRequest` to upload data to . It -will parse the workbook and return an HTML table. - -```jsx live -function SheetJSXHRUL() { - const [__html, setHTML] = React.useState(""); - const [sz, setSz] = React.useState(0); - const csv = "a,b,c\n1,2,3"; - /* Fetch and update HTML */ - const xport = React.useCallback(async() => { - /* Make Workbook from CSV */ - const wb = XLSX.read(csv, { type: "string" }); - - /* Make FormData */ - const data = XLSX.write(wb, {bookType: 'xlsx', type: 'array'}); - setSz(data.length || data.byteLength); - const fdata = new FormData(); - fdata.append('file', new File([data], 'sheetjs.xlsx')); - - /* Upload */ - const url = "https://s2c.sheetjs.com"; - const req = new XMLHttpRequest(); - req.open("POST", url, true); - req.onload = (e) => setHTML(req.responseText); - req.send(fdata); - }); - - return (
-    CSV Data
-    
{csv}
- {sz ? ( <> - Generated file size: {sz} bytes -
- ) : ()} -
); -} -``` - -
### fetch @@ -242,69 +167,17 @@ function SheetJSFetchDL() { -`fetch` takes a second parameter which allows for setting POST request body: - -```js -// assuming `fdata` is a FormData object from "Uploading Binary Data" section -fetch("/upload", { method: "POST", body: fdata }); -``` - -
Live Upload demo (click to show) - -This demo uses `fetch` to upload data to . It will parse -the workbook and return an HTML table. - -```jsx live -function SheetJSFetchUL() { - const [__html, setHTML] = React.useState(""); - const [sz, setSz] = React.useState(0); - const csv = "a,b,c\n1,2,3"; - /* Fetch and update HTML */ - const xport = React.useCallback(async(e) => { - /* Make Workbook from CSV */ - const wb = XLSX.read(csv, { type: "string" }); - const data = XLSX.write(wb, {bookType: 'xlsx', type: 'array'}); - - /* Make FormData */ - setSz(data.length || data.byteLength); - const fdata = new FormData(); - fdata.append('file', new File([data], 'sheetjs.xlsx')); - - /* Upload */ - const url = "https://s2c.sheetjs.com"; - const res = await fetch(url, {method:"POST", body: fdata}); - - /* Set HTML */ - setHTML((await res.text())); - }); - - return (
-    CSV Data
-    
{csv}
- {sz ? ( <> - Generated file size: {sz} bytes -
- ) : ()} -
); -} -``` - -
- - ### jQuery [jQuery](https://jquery.com/) is a JavaScript library that includes helpers for performing "Ajax" network requests. `jQuery.ajax` (`$.ajax`) does not support -binary data out of the box[^1]. A custom `ajaxTransport` can add support. +binary data out of the box[^3]. A custom `ajaxTransport` can add support. -SheetJS users have reported success with `jquery.binarytransport.js`[^2] in IE10. +SheetJS users have reported success with `jquery.binarytransport.js`[^4] in IE10. After including the main `jquery.js` and `jquery.binarytransport.js` scripts, `$.ajax` will support `dataType: "binary"` and `processData: false`. -_Download Files_ - **[Live Download Demo](pathname:///jquery/index.html)** In a GET request, the default behavior is to return a `Blob` object. Passing @@ -399,58 +272,10 @@ function SheetJSAxiosDL() { -Uploading form data is nearly identical to the `fetch` example: - -```js -axios("/upload", { method: "POST", data: fdata }); -``` - -
Live Upload demo (click to show) - -This demo uses `axios` to upload data to . It will parse -the workbook and return an HTML table. - -```jsx live -function SheetJSAxiosUL() { - const [__html, setHTML] = React.useState(""); - const [sz, setSz] = React.useState(0); - const csv = "a,b,c\n1,2,3"; - /* Fetch and update HTML */ - const xport = React.useCallback(async() => { - /* Make Workbook from CSV */ - const wb = XLSX.read(csv, { type: "string" }); - - /* Make FormData */ - const data = XLSX.write(wb, {bookType: 'xlsx', type: 'array'}); - setSz(data.length || data.byteLength); - const fdata = new FormData(); - fdata.append('file', new File([data], 'sheetjs.xlsx')); - - /* Upload */ - const url = "https://s2c.sheetjs.com"; - const res = await axios(url, {method:"POST", data: fdata}); - - /* Set HTML */ - setHTML(res.data); - }); - - return (
-    CSV Data
-    
{csv}
- {sz ? ( <> - Generated file size: {sz} bytes -
- ) : ()} -
); -} -``` - -
- #### superagent [`superagent`](https://github.com/visionmedia/superagent) is a network request -library with a "Fluent Interface"[^3]. Calling the `responseType` method with +library with a "Fluent Interface". Calling the `responseType` method with `"arraybuffer"` will ensure the final response object is an `ArrayBuffer`: ```js @@ -512,56 +337,6 @@ function SheetJSSuperAgentDL() { -The upload portion only differs in the actual request command: - -```js -/* send data (fd is the FormData object) */ -superagent.post("/upload").send(fd); -``` - -
Live Upload demo (click to show) - -This demo uses `superagent` to upload data to . It will -parse the workbook and return an HTML table. - -```jsx live -function SheetJSSuperAgentUL() { - const [__html, setHTML] = React.useState(""); - const [sz, setSz] = React.useState(0); - const csv = "a,b,c\n1,2,3"; - /* Fetch and update HTML */ - const xport = React.useCallback(async() => { - /* Make Workbook from CSV */ - const wb = XLSX.read(csv, { type: "string" }); - - /* Make FormData */ - const data = XLSX.write(wb, {bookType: 'xlsx', type: 'array'}); - setSz(data.length || data.byteLength); - const fdata = new FormData(); - fdata.append('file', new File([data], 'sheetjs.xlsx')); - - /* Upload */ - const url = "https://s2c.sheetjs.com"; - superagent.post(url).send(fdata).end((err, res) => { - /* Set HTML */ - setHTML(res.text); - }); - - }); - - return (
-    CSV Data
-    
{csv}
- {sz ? ( <> - Generated file size: {sz} bytes -
- ) : ()} -
); -} -``` - -
- ## NodeJS Demos These examples show how to download data in NodeJS. @@ -774,6 +549,7 @@ Other demos show network operations in special platforms: - [React Native "Fetching Remote Data"](/docs/demos/mobile/reactnative#fetching-remote-data) - [NativeScript "Fetching Remote Files"](/docs/demos/mobile/nativescript#fetching-remote-files) -[^1]: See [`dataType` in `jQuery.ajax`](https://api.jquery.com/jQuery.ajax/) in the official jQuery documentation. -[^2]: See [the official `jquery.binarytransport.js` repo](https://github.com/henrya/js-jquery/tree/master/BinaryTransport) for more details. -[^3]: See ["Fluent interface"](https://en.wikipedia.org/wiki/Fluent_interface) on Wikipedia. \ No newline at end of file +[^1]: See [`read` in "Reading Files"](/docs/api/parse-options) +[^2]: See [`sheet_to_html` in "Utilities"](/docs/api/utilities/html#html-table-output) +[^3]: See [`dataType` in `jQuery.ajax`](https://api.jquery.com/jQuery.ajax/) in the official jQuery documentation. +[^4]: See [the official `jquery.binarytransport.js` repo](https://github.com/henrya/js-jquery/tree/master/BinaryTransport) for more details. diff --git a/docz/docs/03-demos/03-net/02-upload/_category_.json b/docz/docs/03-demos/03-net/02-upload/_category_.json new file mode 100644 index 0000000..4603ed2 --- /dev/null +++ b/docz/docs/03-demos/03-net/02-upload/_category_.json @@ -0,0 +1,5 @@ +{ + "label": "HTTP Uploads", + "collapsed": false, + "position": 2 +} \ No newline at end of file diff --git a/docz/docs/03-demos/03-net/02-upload/index.mdx b/docz/docs/03-demos/03-net/02-upload/index.mdx new file mode 100644 index 0000000..c0d3ba0 --- /dev/null +++ b/docz/docs/03-demos/03-net/02-upload/index.mdx @@ -0,0 +1,608 @@ +--- +title: HTTP Uploads +pagination_prev: demos/net/network/index +pagination_next: demos/net/server/index +--- + + + + + + +import current from '/version.js'; +import CodeBlock from '@theme/CodeBlock'; + +Browsers and other platforms offer solutions for uploading files to servers and +cloud storage solutions. Spreadsheets can be written using SheetJS and uploaded. + +This demo explores file uploads using a number of browser APIs and wrapper +libraries. The upload process will generate a sample XLSX workbook, upload the +file to [a test server](#test-server), and display the response. + +:::info pass + +This demo focuses on uploading files. Other demos cover other HTTP use cases: + +- ["HTTP Downloads"](/docs/demos/net/network) covers downloading files +- ["HTTP Server Processing"](/docs/demos/net/server) covers HTTP servers + +::: + +:::caution Third-Party Hosts and Binary Data + +Third-party cloud platforms such as AWS may corrupt raw binary uploads by +encoding requests and responses in UTF-8 strings. + +For AWS, in the "Binary Media Types" section of the API Gateway console, the +`"multipart/form-data"` type should be added to ensure that AWS Lambda functions +can receive uploads from clients. + +::: + +## Uploading Binary Data + +The SheetJS `write` method[^1] generates file data stored in `ArrayBuffer` +objects. The `ArrayBuffer` can be added to a `FormData` object. The `FormData` +object can be passed along to POST requests. + +```mermaid +flowchart LR + subgraph SheetJS operations + wb(((SheetJS\nWorkbook))) + ab(XLSX Data\nArrayBuffer) + end + file(File\nobject) + form(FormData\nobject) + server[[Server\nrecipient]] + wb --> |`write`\n\n| ab + ab --> |new\n\n| file + file --> |new\nappend\n| form + form --> |POST\nrequest| server +``` + +```js +/* create sample SheetJS workbook object */ +var aoa = [ + ["S", "h", "e", "e", "t", "J", "S"], + [ 5, 4, 3, 3, 7, 9, 5] +]; +var ws = XLSX.utils.aoa_to_sheet(aoa); +var wb = XLSX.utils.book_new(); +XLSX.utils.book_append_sheet(wb, ws, "Sheet1"); + +/* export SheetJS workbook object to XLSX file bytes */ +var data = XLSX.write(wb, {bookType: 'xlsx', type: 'array'}); + +/* build FormData with the generated file */ +var fdata = new FormData(); +fdata.append('file', new File([data], 'sheetjs.xlsx')); +// field name ^^^^ file name ^^^^^^^^^^^^ + +/* send data using XMLHttpRequest */ +var req = new XMLHttpRequest(); +req.open("POST", "https://s2c.sheetjs.com", true); +req.send(fdata); +``` + +## Test Server + +The service is currently hosted on Deno Deploy. The +["Deno Deploy" demo](/docs/demos/cloud/deno#demo) covers the exact steps for +deploying the service. + +The CORS-enabled service handles POST requests by looking for uploaded files in +the `"file"` key. If a file is found, the file will be parsed using the SheetJS +`read` method[^2] and the first worksheet will be converted to HTML using the +`sheet_to_html` method[^3]. + +## Browser Demos + +When the upload button is clicked, the browser will build up a new workbook, +generate a XLSX file, upload it to and show the +response. If the process was successful, a HTML table will be displayed + +### XMLHttpRequest + +This demo uses [the code snippet from the intro](#uploading-binary-data). + +:::note Tested Deployments + +This browser demo was tested in the following environments: + +| Browser | Date | +|:------------|:-----------| +| Chrome 119 | 2023-11-19 | +| Safari 17.1 | 2023-11-19 | + +::: + +
Live demo (click to show) + +This demo starts from an array of arrays of data. When the button is clicked, a +workbook file will be generated and uploaded to . The +service will return a HTML table. + +```jsx live +function SheetJSXHRUL() { + const [__html, setHTML] = React.useState(""); + const [sz, setSz] = React.useState(0); + const [csv, setCSV] = React.useState(""); + + /* raw data */ + const aoa = [ + ["S", "h", "e", "e", "t", "J", "S"], + [ 5, 4, 3, 3, 7, 9, 5] + ]; + /* target URL */ + const url = "https://s2c.sheetjs.com"; + + /* Fetch and update HTML */ + const xport = React.useCallback(async() => { try { + /* Make SheetJS Workbook from data */ + const ws = XLSX.utils.aoa_to_sheet(aoa); + const wb = XLSX.utils.book_new(); + XLSX.utils.book_append_sheet(wb, ws, "Sheet1"); + + /* Export to XLSX */ + const data = XLSX.write(wb, {bookType: 'xlsx', type: 'array'}); + setSz(data.length || data.byteLength); + + /* Make FormData */ + const fdata = new FormData(); + fdata.append('file', new File([data], 'sheetjs.xlsx')); + + /* Upload */ + /* - create XMLHttpRequest */ + const req = new XMLHttpRequest(); + req.open("POST", url, true); + /* - on success, display the contents */ + req.onload = (e) => setHTML(req.responseText); + /* - on error, display "Request failed" */ + req.onerror = (e) => setHTML("Request failed"); + /* - send data */ + req.send(fdata); + } catch(e) { setHTML(e && e.message || e); } }); + + /* Display data in CSV form */ + React.useEffect(() => { + const ws = XLSX.utils.aoa_to_sheet(aoa); + setCSV(XLSX.utils.sheet_to_csv(ws)); + }, []); + + return (
CSV Data
{csv}
+ {sz ? ( <> + Generated file size: {sz} bytes +
+ ) : ()} +
); +} +``` + +
+ +### fetch + +`fetch` takes a second parameter which allows for setting POST request body: + +```js +/* create sample SheetJS workbook object */ +var aoa = [ + ["S", "h", "e", "e", "t", "J", "S"], + [ 5, 4, 3, 3, 7, 9, 5] +]; +const ws = XLSX.utils.aoa_to_sheet(aoa); +const wb = XLSX.utils.book_new(); +XLSX.utils.book_append_sheet(wb, ws, "Sheet1"); + +/* export SheetJS workbook object to XLSX file bytes */ +var data = XLSX.write(wb, {bookType: 'xlsx', type: 'array'}); + +/* build FormData with the generated file */ +var fdata = new FormData(); +fdata.append('file', new File([data], 'sheetjs.xlsx')); +// field name ^^^^ file name ^^^^^^^^^^^^ + +/* send data using fetch */ +fetch("https://s2c.sheetjs.com", { method: "POST", body: fdata }); +``` + +:::note Tested Deployments + +This browser demo was tested in the following environments: + +| Browser | Date | +|:------------|:-----------| +| Chrome 119 | 2023-11-19 | +| Safari 17.1 | 2023-11-19 | + +::: + +
Live demo (click to show) + +This demo uses `fetch` to upload data to . It will parse +the workbook and return an HTML table. + +```jsx live +function SheetJSFetchUL() { + const [__html, setHTML] = React.useState(""); + const [sz, setSz] = React.useState(0); + const [csv, setCSV] = React.useState(""); + + /* raw data */ + const aoa = [ + ["S", "h", "e", "e", "t", "J", "S"], + [ 5, 4, 3, 3, 7, 9, 5] + ]; + /* target URL */ + const url = "https://s2c.sheetjs.com"; + + /* Fetch and update HTML */ + const xport = React.useCallback(async() => { try { + /* Make SheetJS Workbook from data */ + const ws = XLSX.utils.aoa_to_sheet(aoa); + const wb = XLSX.utils.book_new(); + XLSX.utils.book_append_sheet(wb, ws, "Sheet1"); + + /* Export to XLSX */ + const data = XLSX.write(wb, {bookType: 'xlsx', type: 'array'}); + setSz(data.length || data.byteLength); + + /* Make FormData */ + const fdata = new FormData(); + fdata.append('file', new File([data], 'sheetjs.xlsx')); + + /* Upload */ + const res = await fetch(url, {method:"POST", body: fdata}); + + /* Show Server Response */ + setHTML((await res.text())); + } catch(e) { setHTML(e && e.message || e); }}); + + /* Display data in CSV form */ + React.useEffect(() => { + const ws = XLSX.utils.aoa_to_sheet(aoa); + setCSV(XLSX.utils.sheet_to_csv(ws)); + }, []); + + return (
CSV Data
{csv}
+ {sz ? ( <> + Generated file size: {sz} bytes +
+ ) : ()} +
); +} +``` + +
+ +### Wrapper Libraries + +Before `fetch` shipped with browsers, there were various wrapper libraries to +simplify `XMLHttpRequest`. Due to limitations with `fetch`, these libraries +are still relevant. + +#### axios + +[`axios`](https://axios-http.com/) presents a Promise based interface. + +Uploading form data is nearly identical to the `fetch` example: + +```js +/* create sample SheetJS workbook object */ +var aoa = [ + ["S", "h", "e", "e", "t", "J", "S"], + [ 5, 4, 3, 3, 7, 9, 5] +]; +const ws = XLSX.utils.aoa_to_sheet(aoa); +const wb = XLSX.utils.book_new(); +XLSX.utils.book_append_sheet(wb, ws, "Sheet1"); + +/* export SheetJS workbook object to XLSX file bytes */ +var data = XLSX.write(wb, {bookType: 'xlsx', type: 'array'}); + +/* build FormData with the generated file */ +var fdata = new FormData(); +fdata.append('file', new File([data], 'sheetjs.xlsx')); +// field name ^^^^ file name ^^^^^^^^^^^^ + +/* send data using axios */ +axios("https://s2c.sheetjs.com", { method: "POST", data: fdata }); +``` + +:::note Tested Deployments + +This demo was tested using the standalone script in the following environments: + +| Browser | Version | Date | +|:------------|---------|:-----------| +| Chrome 119 | `1.6.2` | 2023-11-19 | +| Safari 17.1 | `1.6.2` | 2023-11-19 | + +::: + +
Live demo (click to show) + +This demo uses `axios` to upload data to . It will parse +the workbook and return an HTML table. + +:::caution pass + +If the live demo shows a message + +``` +ReferenceError: axios is not defined +``` + +please refresh the page. This is a known bug in the documentation generator. + +::: + +```jsx live +function SheetJSAxiosUL() { + const [__html, setHTML] = React.useState(""); + const [sz, setSz] = React.useState(0); + const [csv, setCSV] = React.useState(""); + + /* raw data */ + const aoa = [ + ["S", "h", "e", "e", "t", "J", "S"], + [ 5, 4, 3, 3, 7, 9, 5] + ]; + /* target URL */ + const url = "https://s2c.sheetjs.com"; + + /* Fetch and update HTML */ + const xport = React.useCallback(async() => { try { + /* Make SheetJS Workbook from data */ + const ws = XLSX.utils.aoa_to_sheet(aoa); + const wb = XLSX.utils.book_new(); + XLSX.utils.book_append_sheet(wb, ws, "Sheet1"); + + /* Export to XLSX */ + const data = XLSX.write(wb, {bookType: 'xlsx', type: 'array'}); + setSz(data.length || data.byteLength); + + /* Make FormData */ + const fdata = new FormData(); + fdata.append('file', new File([data], 'sheetjs.xlsx')); + + /* Upload */ + const res = await axios(url, {method:"POST", data: fdata}); + + /* Show Server Response */ + setHTML(res.data); + } catch(e) { setHTML(e && e.message || e); }}); + + /* Display data in CSV form */ + React.useEffect(() => { + const ws = XLSX.utils.aoa_to_sheet(aoa); + setCSV(XLSX.utils.sheet_to_csv(ws)); + }, []); + + return (
CSV Data
{csv}
+ {sz ? ( <> + Generated file size: {sz} bytes +
+ ) : ()} +
); +} +``` + +
+ +#### superagent + +[`superagent`](https://github.com/visionmedia/superagent) is a network request +library with a "Fluent Interface". + +The `send` method accepts a `FormData` object as the first argument: + +```js +/* create sample SheetJS workbook object */ +var aoa = [ + ["S", "h", "e", "e", "t", "J", "S"], + [ 5, 4, 3, 3, 7, 9, 5] +]; +const ws = XLSX.utils.aoa_to_sheet(aoa); +const wb = XLSX.utils.book_new(); +XLSX.utils.book_append_sheet(wb, ws, "Sheet1"); + +/* export SheetJS workbook object to XLSX file bytes */ +var data = XLSX.write(wb, {bookType: 'xlsx', type: 'array'}); + +/* build FormData with the generated file */ +var fdata = new FormData(); +fdata.append('file', new File([data], 'sheetjs.xlsx')); +// field name ^^^^ file name ^^^^^^^^^^^^ + +/* send data (fd is the FormData object) */ +superagent.post("https://s2c.sheetjs.com").send(fd); +``` + +:::note Tested Deployments + +This demo was tested using the standalone script in the following environments: + +| Browser | Version | Date | +|:------------|---------|:-----------| +| Chrome 119 | `8.1.2` | 2023-11-19 | +| Safari 17.1 | `8.1.2` | 2023-11-19 | + +::: + +
Live demo (click to show) + +This demo uses `superagent` to upload data to . It will +parse the workbook and return an HTML table. + +:::caution pass + +If the live demo shows a message + +``` +ReferenceError: superagent is not defined +``` + +please refresh the page. This is a known bug in the documentation generator. + +::: + +```jsx live +function SheetJSSuperAgentUL() { + const [__html, setHTML] = React.useState(""); + const [sz, setSz] = React.useState(0); + const [csv, setCSV] = React.useState(""); + + /* raw data */ + const aoa = [ + ["S", "h", "e", "e", "t", "J", "S"], + [ 5, 4, 3, 3, 7, 9, 5] + ]; + /* target URL */ + const url = "https://s2c.sheetjs.com"; + + /* Fetch and update HTML */ + const xport = React.useCallback(async() => { try { + /* Make SheetJS Workbook from data */ + const ws = XLSX.utils.aoa_to_sheet(aoa); + const wb = XLSX.utils.book_new(); + XLSX.utils.book_append_sheet(wb, ws, "Sheet1"); + + /* Export to XLSX */ + const data = XLSX.write(wb, {bookType: 'xlsx', type: 'array'}); + setSz(data.length || data.byteLength); + + /* Make FormData */ + const fdata = new FormData(); + fdata.append('file', new File([data], 'sheetjs.xlsx')); + + /* Upload */ + superagent.post(url).send(fdata).end((err, res) => { + /* Show Server Response */ + setHTML(res.text); + }); + } catch(e) { setHTML(e && e.message || e); }}); + + /* Display data in CSV form */ + React.useEffect(() => { + const ws = XLSX.utils.aoa_to_sheet(aoa); + setCSV(XLSX.utils.sheet_to_csv(ws)); + }, []); + + return (
CSV Data
{csv}
+ {sz ? ( <> + Generated file size: {sz} bytes +
+ ) : ()} +
); +} +``` + +
+ +## NodeJS Demos + +These examples show how to upload data in NodeJS. + +### fetch + +The `fetch` implementation mirrors the [browser `fetch`](#fetch). + +:::note Tested Deployments + +This demo was last tested on 2023 November 19 against NodeJS `20.9.0` + +::: + +
Complete Example (click to show) + +This demo uses `fetch` to upload data to . It will parse +the workbook and return data in CSV rows. + +1) Install the [SheetJS NodeJS module](/docs/getting-started/installation/nodejs): + +{`\ +npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz`} + + +2) Save the following to `SheetJSFetch.js`: + +```js title="SheetJSFetch.js" +const XLSX = require("xlsx"); + +/* create sample SheetJS workbook object */ +var aoa = [ + ["S", "h", "e", "e", "t", "J", "S"], + [ 5, 4, 3, 3, 7, 9, 5] +]; +const ws = XLSX.utils.aoa_to_sheet(aoa); +const wb = XLSX.utils.book_new(); +XLSX.utils.book_append_sheet(wb, ws, "Sheet1"); + +/* export SheetJS workbook object to XLSX file bytes */ +var data = XLSX.write(wb, {bookType: 'xlsx', type: 'array'}); + +/* build FormData with the generated file */ +var fdata = new FormData(); +fdata.append('file', new File([data], 'sheetjs.xlsx')); +// field name ^^^^ file name ^^^^^^^^^^^^ +fdata.append('type', 'csv'); + +(async() => { + /* send data using fetch */ + const res = await fetch("https://s2c.sheetjs.com", { method: "POST", body: fdata }); + const txt = await res.text(); + console.log(txt); +})(); +``` + +3) Run the script: + +```bash +node SheetJSFetch.js +``` + +It will print CSV contents of the test file. + +
+ + +## Troubleshooting + +Some SheetJS users have reported corrupted files. To diagnose the error, it is +strongly recommended to write local files. + +For example, using `fetch` in the browser, the bytes can be downloaded using the +[HTML5 Download Attribute](/docs/demos/local/file#html5-download-attribute). The +highlighted lines should be added immediately after `write`: + +```js title="Diagnosing issues in a fetch upload" +/* Generate XLSX file */ +const data = XLSX.write(wb, {bookType: 'xlsx', type: 'array'}); + +// highlight-start +/* Write to Local File */ +const blob = new Blob([data]); +const url = URL.createObjectURL(blob); +const a = document.createElement("a"); +a.download = "SheetJS.xlsx"; +a.href = url; +document.body.appendChild(a); +a.click(); +document.body.removeChild(a); +// highlight-end + +/* Make FormData */ +const fdata = new FormData(); +fdata.append('file', new File([data], 'sheetjs.xlsx')); + +/* Upload */ +const url = "https://s2c.sheetjs.com"; +const res = await fetch(url, {method:"POST", body: fdata}); +``` + +If the generated file is valid, then the issue is in the server infrastructure. + +[^1]: See [`write` in "Writing Files"](/docs/api/write-options) +[^2]: See [`read` in "Reading Files"](/docs/api/parse-options) +[^3]: See [`sheet_to_html` in "Utilities"](/docs/api/utilities/html#html-table-output) diff --git a/docz/docs/03-demos/03-net/02-server/01-express.md b/docz/docs/03-demos/03-net/03-server/01-express.md similarity index 98% rename from docz/docs/03-demos/03-net/02-server/01-express.md rename to docz/docs/03-demos/03-net/03-server/01-express.md index 0f70427..74aa1af 100644 --- a/docz/docs/03-demos/03-net/02-server/01-express.md +++ b/docz/docs/03-demos/03-net/03-server/01-express.md @@ -1,7 +1,7 @@ --- title: Sheets in ExpressJS sidebar_label: ExpressJS -pagination_prev: demos/net/network +pagination_prev: demos/net/network/index pagination_next: demos/net/email/index --- diff --git a/docz/docs/03-demos/03-net/02-server/04-drash.md b/docz/docs/03-demos/03-net/03-server/04-drash.md similarity index 99% rename from docz/docs/03-demos/03-net/02-server/04-drash.md rename to docz/docs/03-demos/03-net/03-server/04-drash.md index dfcb8f1..0ebddee 100644 --- a/docz/docs/03-demos/03-net/02-server/04-drash.md +++ b/docz/docs/03-demos/03-net/03-server/04-drash.md @@ -1,7 +1,7 @@ --- title: Sheets in Drash sidebar_label: Drash -pagination_prev: demos/net/network +pagination_prev: demos/net/network/index pagination_next: demos/net/email/index --- diff --git a/docz/docs/03-demos/03-net/02-server/09-elysia.md b/docz/docs/03-demos/03-net/03-server/09-elysia.md similarity index 99% rename from docz/docs/03-demos/03-net/02-server/09-elysia.md rename to docz/docs/03-demos/03-net/03-server/09-elysia.md index 30c5a15..549ace4 100644 --- a/docz/docs/03-demos/03-net/02-server/09-elysia.md +++ b/docz/docs/03-demos/03-net/03-server/09-elysia.md @@ -1,7 +1,7 @@ --- title: Sheets in Elysia sidebar_label: ElysiaJS -pagination_prev: demos/net/network +pagination_prev: demos/net/network/index pagination_next: demos/net/email/index --- diff --git a/docz/docs/03-demos/03-net/02-server/11-nestjs.md b/docz/docs/03-demos/03-net/03-server/11-nestjs.md similarity index 99% rename from docz/docs/03-demos/03-net/02-server/11-nestjs.md rename to docz/docs/03-demos/03-net/03-server/11-nestjs.md index 0782103..b34bb8b 100644 --- a/docz/docs/03-demos/03-net/02-server/11-nestjs.md +++ b/docz/docs/03-demos/03-net/03-server/11-nestjs.md @@ -1,7 +1,7 @@ --- title: Sheets in NestJS sidebar_label: NestJS -pagination_prev: demos/net/network +pagination_prev: demos/net/network/index pagination_next: demos/net/email/index --- diff --git a/docz/docs/03-demos/03-net/02-server/19-fastify.md b/docz/docs/03-demos/03-net/03-server/19-fastify.md similarity index 98% rename from docz/docs/03-demos/03-net/02-server/19-fastify.md rename to docz/docs/03-demos/03-net/03-server/19-fastify.md index 5898355..2eb92c4 100644 --- a/docz/docs/03-demos/03-net/02-server/19-fastify.md +++ b/docz/docs/03-demos/03-net/03-server/19-fastify.md @@ -1,7 +1,7 @@ --- title: Sheets in FastifyJS sidebar_label: FastifyJS -pagination_prev: demos/net/network +pagination_prev: demos/net/network/index pagination_next: demos/net/email/index --- diff --git a/docz/docs/03-demos/03-net/02-server/_category_.json b/docz/docs/03-demos/03-net/03-server/_category_.json similarity index 78% rename from docz/docs/03-demos/03-net/02-server/_category_.json rename to docz/docs/03-demos/03-net/03-server/_category_.json index ed2370a..500bd1f 100644 --- a/docz/docs/03-demos/03-net/02-server/_category_.json +++ b/docz/docs/03-demos/03-net/03-server/_category_.json @@ -1,5 +1,5 @@ { "label": "HTTP Server Processing", "collapsed": false, - "position": 2 + "position": 3 } \ No newline at end of file diff --git a/docz/docs/03-demos/03-net/02-server/index.md b/docz/docs/03-demos/03-net/03-server/index.md similarity index 96% rename from docz/docs/03-demos/03-net/02-server/index.md rename to docz/docs/03-demos/03-net/03-server/index.md index 360f703..6637097 100644 --- a/docz/docs/03-demos/03-net/02-server/index.md +++ b/docz/docs/03-demos/03-net/03-server/index.md @@ -1,6 +1,6 @@ --- title: HTTP Server Processing -pagination_prev: demos/net/network +pagination_prev: demos/net/upload/index pagination_next: demos/net/email/index --- @@ -10,6 +10,15 @@ import CodeBlock from '@theme/CodeBlock'; Server-Side JS platforms like NodeJS and Deno have built-in APIs for listening on network interfaces. They provide wrappers for requests and responses. +:::info pass + +This demo focuses on HTTP servers. Other demos cover other HTTP use cases: + +- ["HTTP Downloads"](/docs/demos/net/network) covers downloading files +- ["HTTP Uploads"](/docs/demos/net/upload) covers uploading files + +::: + ## Overview #### Parsing Files in POST Requests