---
title: Sheets on Fire with HonoJS
sidebar_label: HonoJS
pagination_prev: demos/net/network/index
pagination_next: demos/net/email/index
---
import current from '/version.js';
import CodeBlock from '@theme/CodeBlock';
[HonoJS](https://hono.dev/) is a lightweight server-side framework.
[SheetJS](https://sheetjs.com) is a JavaScript library for reading and writing
data from spreadsheets.
This demo uses HonoJS 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 Tested Deployments
This demo was last tested in the following deployments:
| Platform | HonoJS | Date |
|:---------------|:--------|:-----------|
| BunJS `1.1.21` | `4.5.1` | 2024-07-27 |
:::
## Integration Details
The [SheetJS BunJS module](/docs/getting-started/installation/bun) can be
imported from HonoJS server scripts.
### Reading Data
The HonoJS body parser[^1] processes files in POST requests. The body parser
returns an object that can be indexed by field name:
```js
/* /import route */
app.post('/import', async(c) => {
/* parse body */
const body = await c.req.parseBody();
/* get a file uploaded in the `upload` field */
// highlight-next-line
const file = body["upload"];
/* `file` is a `File` object */
// ...
});
```
:::caution pass
By default, the HonoJS body parser will use the last value when the form body
specifies multiple values for a given field. To force the body parser to process
all files, the field name must end with `[]`:
```js
/* parse body */
const body = await c.req.parseBody();
/* get all files uploaded in the `upload` field */
// highlight-next-line
const files = body["upload[]"];
```
:::
HonoJS exposes each 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` method[^2].
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 and, generate CSV rows using the `sheet_to_csv` method[^3],
and respond with text:
```js
import { Hono } from 'hono';
import { read, utils } from 'xlsx';
const app = new Hono();
app.post('/import', async(c) => {
/* get file data */
const body = await c.req.parseBody();
const file = body["upload"];
const ab = await file.arrayBuffer();
/* parse */
const wb = read(ab);
/* generate CSV */
const csv = utils.sheet_to_csv(wb.Sheets[wb.SheetNames[0]]);
return c.text(csv);
});
export default app;
```
### Writing Data
Given a SheetJS workbook object, the `write` method using `type: "buffer"`[^4]
generates data objects which can be passed to the response `body` method.
This example server responds to GET requests. The server will generate a SheetJS
worksheet object from an array of arrays[^5], build up a new workbook using the
`book_new`[^6] utility method, generate a XLSX file using `write`, and send the
file with appropriate headers to download `SheetJSHonoJS.xlsx`:
```js
import { Hono } from 'hono';
import { utils, write } from "xlsx";
const app = new Hono();
app.get("/export", (c) => {
/* generate SheetJS workbook object */
var ws = utils.aoa_to_sheet(["SheetJS".split(""), [5,4,3,3,7,9,5]]);
var wb = utils.book_new(ws, "Data");
/* generate buffer */
var buf = write(wb, {type: "buffer", bookType: "xlsx"});
/* set headers */
c.header('Content-Disposition', 'attachment; filename="SheetJSHonoJS.xlsx"');
c.header('Content-Type', 'application/vnd.ms-excel');
/* export buffer */
return c.body(buf);
});
export default app;
```
## Complete Example
This example creates a simple server that stores an array of arrays. There are
three server endpoints:
- `/import` POST request expects a file in the `upload` field. It will parse the
file, update the internal array of arrays, and responds with CSV data.
- `/export` GET request generates a workbook from the internal array of arrays.
It will respond with XLSX data and initiate a download to `SheetJSHonoJS.xlsx` .
- `/json` GET request responds with the internal state.
1) Create a new BunJS + HonoJS project:
```bash
bun create hono sheetjs-hono --template bun --install --pm bun
cd sheetjs-hono
```
2) Install the [SheetJS BunJS module](/docs/getting-started/installation/bun):
S | h | e | e | t | J | S |
5 | 4 | 3 | 3 | 7 | 9 | 5 |