Splitting and Serving PDF Files Efficiently with Firebase Storage and Buffer in Node.js(The knight way⚔️)
Tags: typescript, express, firebase, node
Published: 2023-05-24 14:22:10

## PROLOGUE 🛡️⚜️🛡️

In the land of coding, where clients' wishes reign supreme, I stumbled upon a formidable challenge. The task at hand was to tame a wild PDF, splitting its unruly pages to keep the browser from throwing a fit. With the mighty Firebase Storage and the trusty Buffer by my side, I embarked on an epic quest. Join me as I unravel the secrets of slaying lag times and serving PDFs with finesse!

## CHAPTER ONE🤺🤺(The Code)

Once upon a time, in a digital realm not so far away, there was a mischievous PDF named "example.pdf." It was a hefty creature, notorious for causing browser mayhem and frustrating users with its laggy ways. Our brave developer, armed with code and determination, sought to bring order to this unruly document. Let's dive into the enchanted forest of code and witness the magic unfold:

```typescript
import { RequestHandler } from 'express';
import { Config } from '../../../utils/config';
import { getFilePath } from '../../../utils/helpers/common';
const { Storage } = require('@google-cloud/storage');
import * as mime from 'mime';
const { PDFDocument } = require('pdf-lib');

export const getBookFileWithRange: RequestHandler = async (req: any, res) => {
  const dummyFileURL = 'https://dummy-firebase-storage.com/books/example.pdf';
  
  // Behold! The filename of our fearless PDF hero!
  const filename = 'example.pdf';

  // Preparing our trusty steed, the Firebase Storage
  const storage = new Storage();

  try {
    const bucket = storage.bucket(Config.storageBucket);
    const fileName = filename;

    // Venturing into Firebase Storage to fetch the mythical file
    const file = await bucket.file(filename);

    // Slaying the PDF dragon, one byte at a time
    const [fileBuffer] = await file.download();

    // Unlocking the ancient secrets of pdf-lib
    const firstDonorPdfDoc = await PDFDocument.load(new Uint8Array(Buffer.from(fileBuffer)));

    // Creating an empty canvas for our newly crafted PDF masterpiece
    const pdfDoc = await PDFDocument.create();
    let start: number = Number(req.query.startPage);
    let pageCount = 0;
    let end: number = Number(req.query.endPage);

    // Carefully selecting and copying the desired pages
    for (start - 1; start - 1 <= end - 1; start++) {
      const [page] = await pdfDoc.copyPages(firstDonorPdfDoc, [start - 1]);
      pdfDoc.insertPage(pageCount, page);
      pageCount++;
    }

    // Polishing our creation, preparing it for the grand reveal
    const pdfBytes = await pdfDoc.save();

    // Identifying the magical essence of our creation (the content type)
    const contentType = mime.getType(fileName);

    // Announcing to the world the type of our creation
    res.set('Content-Type', contentType?.toString());

    // The moment of triumph has arrived! Sending our masterpiece to the waiting world
    return res.status(200).send(Buffer.from(pdfBytes));
  } catch (error) {
    console.error('Oh no! The dragon proved too fierce:', error);
    return res.status(500).send('Error downloading file');
  }
};
```
#CHAPTER TWO🗡️⚔️(The deep dive) 

In our whimsical adventure, we rely on several magical artifacts:

`Express`: The brave and reliable Express framework, guiding us through the treacherous routes of the web.

`pdf-lib`: A wizardly library that lets us wield the power of PDF manipulation, enabling us to split, copy, and create PDF documents with ease.

`Firebase Storage`: A mystical cloud storage service, granting us the power to store and retrieve files securely.

`mime`: A tiny library that helps us unveil the true identity of our PDF, revealing its content type to the awaiting world.

##CHAPTER 3🛡🛡(The server side)

In this whimsical tale, we not only embarked on a quest to split and serve PDF files but also discovered the magic of connecting our code to the server. Let's take a closer look at how we can integrate the PDF splitting functionality into our index.js or server.js file:
```typescript
import cors from 'cors';
import express from 'express';
import { getBookFileWithRange } from './handlers/get/books/getBookFile';

const app = express();
app.use(cors());

// Endpoint for serving PDF files with page range
app.get('/book/file/by/url/:filename', getBookFileWithRange);

// Your other API endpoints can be added here

// Start the server
app.listen(3000, () => {
  console.log('Server is running on port 3000');
});

```
In the above code snippet, we first import the necessary libraries, such as cors and express, to handle server-related functionality. We then import the getBookFileWithRange function from our PDF handling module.

Next, we create an instance of the Express application, configure it to use the cors middleware, and define our API endpoint for serving PDF files with a specific page range. You can add additional endpoints and routes to cater to your specific application needs.

Finally, we start the server by calling the listen method and specifying the port number on which the server should listen. In this case, I set it to port 3000, but you can modify it according to your requirements.


## CHAPTER 4⚔️(Making the API Call)

Now that we have our splendid server up and running, it's time to unleash its powers by making an API call to retrieve our perfectly tailored PDF. The API endpoint we'll be hitting is `/book/file/by/url/:filename`, and it accepts a few query parameters to customize the output. Let's dive in and explore how we can make the most of it!

### Endpoint

```
GET /book/file/by/url/:filename
```

### Query Parameters

1. `startPage` (required): Specifies the starting page number from where the PDF should be split. Must be a positive integer.

2. `endPage` (required): Specifies the ending page number until where the PDF should be split. Must be a positive integer greater than or equal to the `startPage`.

##CHAPTER 5 ⚜️(The end)

With these enchanting tools in our possession, we embark on our noble quest to slay the dreaded lag times and deliver perfectly tailored PDFs to our users. The code comes alive, executing each step with precision and grace.

In conclusion, by combining the capabilities of Firebase Storage, the pdf-lib library, and the Buffer object, we can efficiently split and serve PDF files in a secure and optimized manner. This solution allows for flexibility in managing large PDF files while ensuring a smooth user experience.

And now, as the sun sets on our coding adventure, I, Knight⚔️ Collins, must bid you farewell. Don't forget to like❤️,🦄 and share😁.