187 lines
6.0 KiB
Markdown
187 lines
6.0 KiB
Markdown
|
---
|
||
|
title: Sheets in FastifyJS
|
||
|
sidebar_label: FastifyJS
|
||
|
pagination_prev: demos/net/network
|
||
|
pagination_next: demos/net/email
|
||
|
---
|
||
|
|
||
|
import current from '/version.js';
|
||
|
import CodeBlock from '@theme/CodeBlock';
|
||
|
|
||
|
[FastifyJS](https://openjsf.org/projects/) is a NodeJS web framework.
|
||
|
|
||
|
[SheetJS](https://sheetjs.com) is a JavaScript library for reading and writing
|
||
|
data from spreadsheets.
|
||
|
|
||
|
This demo uses FastifyJS and SheetJS to read and write data. We'll explore how
|
||
|
to parse uploaded files in a POST request handler and respond to GET requests
|
||
|
with downloadable spreadsheets.
|
||
|
|
||
|
The ["Complete Example"](#complete-example) section includes a complete server.
|
||
|
|
||
|
:::note
|
||
|
|
||
|
This demo was verified on 2023 October 16 using `fastify@4.24.2`
|
||
|
|
||
|
:::
|
||
|
|
||
|
## Integration Details
|
||
|
|
||
|
The [SheetJS NodeJS module](/docs/getting-started/installation/nodejs) can be
|
||
|
imported from scripts that use FastifyJS.
|
||
|
|
||
|
### Exporting Data to Workbooks (GET)
|
||
|
|
||
|
The SheetJS `write` method[^1] with the option `type: "buffer"` generates NodeJS
|
||
|
Buffer objects containing the raw file data.
|
||
|
|
||
|
FastifyJS can directly handle `Buffer` data in `Response#end`
|
||
|
|
||
|
The exported filename can be specified using the `Content-Disposition` header.
|
||
|
|
||
|
The following demo FastifyJS server will respond to GET requests to `/download`
|
||
|
with a XLSX spreadsheet. In this example, the SheetJS `aoa_to_sheet` method[^2]
|
||
|
generates a sheet object and the `book_new` and `book_append_sheet` helpers[^3]
|
||
|
build the workbook object.
|
||
|
|
||
|
```js
|
||
|
/* GET / returns a workbook */
|
||
|
fastify.get('/', (req, reply) => {
|
||
|
/* make a workbook */
|
||
|
var wb = XLSX.read("S,h,e,e,t,J,S\n5,4,3,3,7,9,5", {type: "binary"});
|
||
|
|
||
|
/* write to Buffer */
|
||
|
const buf = XLSX.write(wb, {type:"buffer", bookType: "xlsx"});
|
||
|
|
||
|
/* set Content-Disposition header and send data */
|
||
|
// highlight-next-line
|
||
|
reply.header('Content-Disposition', 'attachment; filename="SheetJSFastify.xlsx"').send(buf);
|
||
|
});
|
||
|
```
|
||
|
|
||
|
### Parsing Uploaded Files (POST)
|
||
|
|
||
|
`@fastify/multipart`, which uses `busbuy` under the hood, must be registered:
|
||
|
|
||
|
```js
|
||
|
/* load SheetJS Library */
|
||
|
const XLSX = require("xlsx");
|
||
|
/* load fastify and enable body parsing */
|
||
|
const fastify = require('fastify')({logger: true});
|
||
|
// highlight-next-line
|
||
|
fastify.register(require('@fastify/multipart'), { attachFieldsToBody: true });
|
||
|
```
|
||
|
|
||
|
Once registered with the option `attachFieldsToBody`, route handlers can use
|
||
|
`req.body` directly.
|
||
|
|
||
|
Each file object in the body has a `toBuffer` method that resolves to a Buffer
|
||
|
object. The SheetJS `read` method[^4] can read the Buffer and generate a
|
||
|
workbook object[^5].
|
||
|
|
||
|
The following demo FastifyJS server will respond to POST requests to `/upload`.
|
||
|
Assuming the `upload` field of the form data is the file, the SheetJS `read`
|
||
|
method will parse the file. CSV rows are generated from the first worksheet
|
||
|
using the SheetJS `sheet_to_csv` method[^6].
|
||
|
|
||
|
```js
|
||
|
/* POST / reads submitted file and exports to requested format */
|
||
|
fastify.post('/', async(req, reply) => {
|
||
|
/* "file" is the name of the field in the HTML form*/
|
||
|
const file = req.body.upload;
|
||
|
/* toBuffer returns a promise that resolves to a Buffer */
|
||
|
// highlight-next-line
|
||
|
const buf = await file.toBuffer();
|
||
|
/* `XLSX.read` can read the Buffer */
|
||
|
const wb = XLSX.read(buf);
|
||
|
/* reply with a CSV */
|
||
|
reply.send(XLSX.utils.sheet_to_csv(wb.Sheets[wb.SheetNames[0]]));
|
||
|
});
|
||
|
```
|
||
|
|
||
|
:::caution pass
|
||
|
|
||
|
Out of the box, Fastify will return an error `FST_ERR_CTP_BODY_TOO_LARGE` when
|
||
|
processing large spreadsheets (`statusCode 413`). This is a Fastify issue.
|
||
|
|
||
|
The default body size limit (including all uploaded files and fields) is 1 MB.
|
||
|
It can be increased by setting the `bodyLimit` option during server creation:
|
||
|
|
||
|
```js
|
||
|
/* increase request body size limit to 5MB = 5 * 1024 * 1024 bytes */
|
||
|
const fastify = require('fastify')({bodyLimit: 5 * 1024 * 1024});
|
||
|
```
|
||
|
|
||
|
:::
|
||
|
|
||
|
## Complete Example
|
||
|
|
||
|
0) Save the following snippet to `SheetJSFastify.js`:
|
||
|
|
||
|
```js title="SheetJSFastify.js"
|
||
|
/* load SheetJS Library */
|
||
|
const XLSX = require("xlsx");
|
||
|
/* load fastify and enable body parsing */
|
||
|
const fastify = require('fastify')({logger: true});
|
||
|
fastify.register(require('@fastify/multipart'), { attachFieldsToBody: true });
|
||
|
|
||
|
/* GET / returns a workbook */
|
||
|
fastify.get('/', (req, reply) => {
|
||
|
/* make a workbook */
|
||
|
var wb = XLSX.read("S,h,e,e,t,J,S\n5,4,3,3,7,9,5", {type: "binary"});
|
||
|
|
||
|
/* write to Buffer */
|
||
|
const buf = XLSX.write(wb, {type:"buffer", bookType: "xlsx"});
|
||
|
|
||
|
/* set Content-Disposition header and send data */
|
||
|
reply.header('Content-Disposition', 'attachment; filename="SheetJSFastify.xlsx"').send(buf);
|
||
|
});
|
||
|
|
||
|
/* POST / reads submitted file and exports to requested format */
|
||
|
fastify.post('/', async(req, reply) => {
|
||
|
|
||
|
/* "file" is the name of the field in the HTML form*/
|
||
|
const file = req.body.upload;
|
||
|
|
||
|
/* toBuffer returns a promise that resolves to a Buffer */
|
||
|
const wb = XLSX.read(await file.toBuffer());
|
||
|
|
||
|
/* send back a CSV */
|
||
|
reply.send(XLSX.utils.sheet_to_csv(wb.Sheets[wb.SheetNames[0]]));
|
||
|
});
|
||
|
|
||
|
/* start */
|
||
|
fastify.listen({port: process.env.PORT || 3000}, (err, addr) => { if(err) throw err; });
|
||
|
```
|
||
|
|
||
|
1) Install dependencies:
|
||
|
|
||
|
<CodeBlock language="bash">{`\
|
||
|
npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz fastify@4.24.2 @fastify/multipart@8.0.0`}
|
||
|
</CodeBlock>
|
||
|
|
||
|
2) Start server
|
||
|
|
||
|
```bash
|
||
|
node SheetJSFastify.js
|
||
|
```
|
||
|
|
||
|
3) Test POST requests using <https://sheetjs.com/pres.numbers>:
|
||
|
|
||
|
```bash
|
||
|
curl -LO https://sheetjs.com/pres.numbers
|
||
|
curl -X POST -F upload=@pres.numbers http://localhost:3000/
|
||
|
```
|
||
|
|
||
|
The response should show the data in CSV rows.
|
||
|
|
||
|
4) Test GET requests by opening `http://localhost:3000/` in your browser.
|
||
|
|
||
|
It should prompt to download `SheetJSFastify.xlsx`
|
||
|
|
||
|
[^1]: See [`write` in "Writing Files"](/docs/api/write-options)
|
||
|
[^2]: See [`aoa_to_sheet` in "Utilities"](/docs/api/utilities/array#array-of-arrays-input)
|
||
|
[^3]: See ["Workbook Helpers" in "Utilities"](/docs/api/utilities/wb) for details on `book_new` and `book_append_sheet`.
|
||
|
[^4]: See [`readFile` in "Reading Files"](/docs/api/parse-options)
|
||
|
[^5]: See ["Workbook Object"](/docs/csf/book)
|
||
|
[^6]: See [`sheet_to_csv` in "CSV and Text"](/docs/api/utilities/csv#delimiter-separated-output)
|