| 
									
										
										
										
											2018-03-29 04:31:36 +00:00
										 |  |  | # "Serverless" Functions
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Because the library is pure JS, the hard work of reading and writing files can | 
					
						
							|  |  |  | be performed in the client browser or on the server side.  On the server side, | 
					
						
							|  |  |  | the mechanical process is essentially independent from the data parsing or | 
					
						
							|  |  |  | generation.  As a result, it is sometimes sensible to organize applications so | 
					
						
							|  |  |  | that the "last mile" conversion between JSON data and spreadsheet files is | 
					
						
							|  |  |  | independent from the main application. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-15 01:46:49 +00:00
										 |  |  | The straightforward architecture would split off the JSON data conversion as a | 
					
						
							| 
									
										
										
										
											2018-03-29 04:31:36 +00:00
										 |  |  | separate microservice or application.  Since it is only needed when an import or | 
					
						
							|  |  |  | export is requested, and since the process itself is relatively independent from | 
					
						
							|  |  |  | the rest of a typical service, a "Serverless" architecture makes a great fit. | 
					
						
							| 
									
										
										
										
											2019-11-15 01:46:49 +00:00
										 |  |  | Since the "function" is separate from the rest of the application, it can be | 
					
						
							|  |  |  | integrated into a platform built in Java or Go or Python or another language! | 
					
						
							| 
									
										
										
										
											2018-03-29 04:31:36 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | This demo discusses general architectures and provides examples for popular | 
					
						
							|  |  |  | commercial systems and self-hosted alternatives.  The examples are merely | 
					
						
							|  |  |  | intended to demonstrate very basic functionality. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ## Simple Strategies
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #### Data Normalization
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Most programming languages and platforms can process CSV or JSON but can't use | 
					
						
							|  |  |  | XLS or XLSX or XLSB directly.  Form data from an HTTP POST request can be parsed | 
					
						
							|  |  |  | and contained files can be converted to CSV or JSON.  The `XLSX.stream.to_csv` | 
					
						
							|  |  |  | utility can stream rows to a standard HTTP response.  `XLSX.utils.sheet_to_json` | 
					
						
							|  |  |  | can generate an array of objects that can be fed to another service. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | At the simplest level, a file on the filesystem can be converted using the bin | 
					
						
							|  |  |  | script that ships with the `npm` module: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```bash | 
					
						
							|  |  |  | $ xlsx /path/to/uploads/file > /tmp/new_csv_file | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | From a utility script, workbooks can be converted in two lines: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```js | 
					
						
							|  |  |  | var workbook = XLSX.readFile("path/to/file.xlsb"); | 
					
						
							|  |  |  | XLSX.writeFile(workbook, "output/path/file.csv"); | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | The `mcstream.js` demo uses the `microcule` framework to show a simple body | 
					
						
							|  |  |  | converter.  It accepts raw data from a POST connection, parses as a workbook, | 
					
						
							|  |  |  | and streams back the first worksheet as CSV: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | <details> | 
					
						
							|  |  |  | 	<summary><b>Code Sketch</b> (click to show)</summary> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```js | 
					
						
							|  |  |  | const XLSX = require('xlsx'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | module.exports = (hook) => { | 
					
						
							|  |  |  | 	/* process_RS from the main README under "Streaming Read" section */ | 
					
						
							|  |  |  | 	process_RS(hook.req, (wb) => { | 
					
						
							|  |  |  | 		hook.res.writeHead(200, { 'Content-Type': 'text/csv' }); | 
					
						
							|  |  |  | 		/* get first worksheet */ | 
					
						
							|  |  |  | 		const ws = wb.Sheets[wb.SheetNames[0]]; | 
					
						
							|  |  |  | 		/* generate CSV stream and pipe to response */ | 
					
						
							|  |  |  | 		const stream = XLSX.stream.to_csv(ws); | 
					
						
							|  |  |  | 		stream.pipe(hook.res); | 
					
						
							|  |  |  | 	}); | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | </details> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #### Report Generation
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-15 01:46:49 +00:00
										 |  |  | For an existing platform that already generates JSON or CSV or HTML output, the | 
					
						
							|  |  |  | library can process the data and generate a new file with embellishments. The | 
					
						
							| 
									
										
										
										
											2018-03-29 04:31:36 +00:00
										 |  |  | `XLSX.utils.sheet_add_json` and `XLSX.utils.sheet_add_aoa` functions can add | 
					
						
							|  |  |  | data rows to an existing worksheet: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```js | 
					
						
							|  |  |  | var ws = XLSX.utils.aoa_to_sheet([ | 
					
						
							|  |  |  | 	["Company Report"], | 
					
						
							|  |  |  | 	[], | 
					
						
							|  |  |  | 	["Item", "Cost"] | 
					
						
							|  |  |  | ]); | 
					
						
							|  |  |  | XLSX.utils.sheet_add_json(ws, [ | 
					
						
							|  |  |  | 	{ item: "Coffee", cost: 5 }, | 
					
						
							|  |  |  | 	{ item: "Cake", cost: 20 } | 
					
						
							|  |  |  | ], { skipHeader: true, origin: -1, header: ["item", "cost"] }); | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ## Deployment Targets
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | The library is supported in Node versions starting from `0.8` as well as a | 
					
						
							|  |  |  | myriad of ES3 and ES5 compatible JS engines.  All major services use Node | 
					
						
							|  |  |  | versions beyond major release 4, so there should be no problem directly using | 
					
						
							|  |  |  | the library in those environments. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Note that most cloud providers proactively convert form data to UTF8 strings. | 
					
						
							|  |  |  | This is especially problematic when dealing with XLSX and XLSB files, as they | 
					
						
							|  |  |  | naturally contain codes that are not valid UTF8 characters.  As a result, these | 
					
						
							|  |  |  | demos specifically handle Base64-encoded files only.  To test on the command | 
					
						
							|  |  |  | line, use the `base64` tool to encode data before piping to `curl`: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | base64 test.xlsb | curl -F "data=@-;filename=test.xlsb" http://localhost/ | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #### AWS Lambda
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Through the AWS Gateway API, Lambda functions can be triggered on HTTP requests. | 
					
						
							|  |  |  | The `LambdaProxy` example reads files from form data and converts to CSV. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | When deploying on AWS, be sure to `npm install` locally and include the modules | 
					
						
							|  |  |  | in the ZIP file. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-04 03:03:42 +00:00
										 |  |  | When reading form data, be sure to include the necessary binary types on the AWS API Gateway console. | 
					
						
							|  |  |  | To do this, navigate to the "Binary Media Types" section in the settings tab of the console. | 
					
						
							| 
									
										
										
										
											2021-08-11 02:53:38 +00:00
										 |  |  | For reading a file, you may need to add `"multipart/form-data"`. | 
					
						
							|  |  |  | For downloading a file, you may need to add `"application/vnd.ms-excel"`. | 
					
						
							| 
									
										
										
										
											2021-05-04 03:03:42 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-29 04:31:36 +00:00
										 |  |  | #### Azure Functions
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Azure supports many types of triggers.  The `AzureHTTPTrigger` shows an example | 
					
						
							|  |  |  | HTTP trigger that converts the submitted file to CSV. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | When deploying on Azure, be sure to install the module from the remote console, | 
					
						
							|  |  |  | as described in the "Azure Functions JavaScript developer guide". | 
					
						
							| 
									
										
										
										
											2020-06-25 19:30:56 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | #### Firebase Functions
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Firebase functions can be triggered via HTTP requests, similar to a REST API. | 
					
						
							|  |  |  | In the `Firebase` directory, the example function reads files sent through | 
					
						
							|  |  |  | HTTP and converts it to a CSV and sends the response in the form of a string. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | To run this demo locally, run `npm i -g firebase-tools` to install the | 
					
						
							|  |  |  | Firebase CLI and `npm i` to install the dependencies, then `firebase use --add` | 
					
						
							|  |  |  | to connect to an existing Firebase project. Run `firebase emulators:start` to | 
					
						
							|  |  |  | start the local server. |