Sheets in Elysia
Elysia is a BunJS server-side framework.
SheetJS is a JavaScript library for reading and writing data from spreadsheets.
This demo uses ElysiaJS 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" section includes a complete server.
This demo was last tested on 2024 March 11 with ElysiaJS 0.8.17 and BunJS 1.0.30.
Integration Details​
The SheetJS BunJS module can be imported from ElysiaJS server scripts.
Reading Data​
The ElysiaJS body parser accepts a schema1. The t.File
method marks that a
field is expected to be a file.
The following schema indicates the field upload
should be a submitted file:
{
body: t.Object({
upload: t.File()
})
}
ElysiaJS exposes the file as a Blob
object. The Blob#arrayBuffer
method
returns a Promise that resolves to an ArrayBuffer
. That ArrayBuffer
can be
parsed with the SheetJS read
method2.
This example server responds to POST requests. The server will look for a file
in the request body under the "upload"
key. If a file is present, the server
will parse the file, generate an HTML table using the sheet_to_html
method3
and respond with the HTML code:
import { Elysia, t } from "elysia";
import { read, utils } from "xlsx";
const app = new Elysia();
app.post("/", async({ body: { upload } }) => {
const data = await upload.arrayBuffer();
const wb = read(data);
return utils.sheet_to_csv(wb.Sheets[wb.SheetNames[0]]);
}, {
body: t.Object({
upload: t.File()
})
});
app.listen(3000);
Writing Data​
Given a SheetJS workbook object, the write
method using type: "buffer"
4
generates data objects which can be passed to the BunJS File
constructor. The
File
constructor accepts a second parameter for the generated file name.
This example server responds to GET requests. The server will generate a SheetJS
worksheet object from an array of arrays5, build up a new workbook using the
book_new
6 and book_append_sheet
7 utility methods, generate a XLSX file
using write
, and send the file with appropriate headers to initiate a download
with file name SheetJSElysia.xlsx
:
import { Elysia } from "elysia";
import { utils, write } from "xlsx";
const app = new Elysia();
app.get("/", () => {
var ws = utils.aoa_to_sheet(["SheetJS".split(""), [5,4,3,3,7,9,5]]);
var wb = utils.book_new(); utils.book_append_sheet(wb, ws, "Data");
/* generate buffer */
var buf = write(wb, {type: "buffer", bookType: "xlsx"});
return new File([buf], "SheetJSElysia.xlsx");
});
app.listen(3000);
Complete Example​
- Create a new ElysiaJS project:
bun create elysia sheetjs-elysia
cd sheetjs-elysia
- Install the SheetJS BunJS module:
bun install https://cdn.sheetjs.com/xlsx-0.20.3/xlsx-0.20.3.tgz
- Save the following script to
src/SheetJSElysia.ts
:
import { Elysia, t } from "elysia";
import { read, utils, write } from "xlsx";
const app = new Elysia();
app.get("/", () => {
var ws = utils.aoa_to_sheet(["SheetJS".split(""), [5,4,3,3,7,9,5]]);
var wb = utils.book_new(); utils.book_append_sheet(wb, ws, "Data");
/* generate buffer */
var buf = write(wb, {type: "buffer", bookType: "xlsx"});
return new File([buf], "SheetJSElysia.xlsx");
/* set headers */
});
app.post("/", async({ body: { upload } }) => {
const data = await upload.arrayBuffer();
const wb = read(data);
return utils.sheet_to_csv(wb.Sheets[wb.SheetNames[0]]);
}, {
body: t.Object({
upload: t.File()
})
});
app.listen(3000);
- Run the server:
bun run src/SheetJSElysia.ts
- Test POST requests using https://docs.sheetjs.com/pres.numbers . The commands should be run in a new terminal window:
curl -LO https://docs.sheetjs.com/pres.numbers
curl -X POST -F upload=@pres.numbers http://localhost:3000/
- Test GET requests by opening
http://localhost:3000/
in your browser.
The page should attempt to download SheetJSElysia.xlsx
. Open the new file.
Footnotes​
-
See "Explicit Body" in the ElysiaJS documentation. ↩