How to upload files with Node.js and Hapi.js

How to upload files with Node.js and Hapi.js

  • 607

This post I just noted for myself what I learned after implemented handle files upload with **Hapi.js** (In the past, I used to handle file upload but with Express.js + Multer) In this post it’s different but very easier to implement.

This post I just noted for myself what I learned after implemented handle files upload with Hapi.js (In the past, I used to handle file upload but with Express.js + Multer) In this post it’s different but very easier to implement.

Create Project

I initial project with yarn init and add dependencies:

yarn init
yarn add hapi inert
  • Hapi: Hapi library
  • Inert: Static file and directory handlers for Hapi.js

First step, I create a simple server with Hapi.js that running on port 2345

const Hapi = require('hapi')
const Inert = require('inert')
const server = Hapi.Server({ port: 2345 })
const init = async () => {
  await server.register(Inert)
  server.route({
    path: '/',
    method: 'GET',
    handler: (req, h) => ({ message: 'Hello Hapi.js' })
  })
  await server.start()
}
init()

After that, verify that Hapi Server is running

nodemon server.js

We will see message like this

{
  "message": "Hello Hapi.js"
}

Now, I know Hapi is working, next step is to create the endpoint for receiving a file, then I decided to create the endpoint with POST method like this:

server.route({
  path: '/upload',
  method: 'POST',
  handler: (req, h) => {
    const { payload } = req
    return payload
  }
})

This is image title

Next, I upload an image with key file and use form-data to send a request to a server, the server responds with Buffer

{
  "file": {
    "type": "Buffer",
    "data": []
  }
}

This is image title
As you see, we received the response with Buffer, we able to write a file with fs module like this:

const fs = require('fs')
fs.writeFile('filename.png', BUFFER_DATA, err => {
  if (!err) {
    console.log('Uploaded!')
  }
})

I decided to create function to handle payload, I know only it’s Buffer but I don’t know a name of file then I hard code a filename to test.png 😄

const handleFileUpload = file => {
 return new Promise((resolve, reject) => {
   fs.writeFile('./upload/test.png', file, err => {
      if (err) {
       reject(err)
      }
      resolve({ message: 'Upload successfully!' })
   })
 })
}

Implement with routing

server.route({
  path: '/upload',
  method: 'POST',
  handler: async (req, h) => {
    const { payload } = req
    const response = handleFileUpload(payload.file)
    return response
  }
})

And I test to upload my image, its working! 🎉

.
├── node_modules
├── package.json
├── server.js
├── upload
│   └── test.png
└── yarn.lock

Using Inert and Options

I already handle my image but overall it not good because I don’t know a file name. Lucky, Hapi.js provided an options for you I also added options to make response return as a stream.

server.route({
  path: '/upload',
  method: 'POST',
  options: {
    payload: {
      output: 'stream',
    }
  },
  handler: async (req, h) => {
    const { payload } = req
    const response = handleFileUpload(payload.file)
    return response
  }
})

This is image title
As you see, response return stream, and contains information about filename, headers, then I updated my handleFileUpload function to write a file to

const handleFileUpload = file => {
  return new Promise((resolve, reject) => {
    const filename = file.hapi.filename
    const data = file._data
    fs.writeFile('./upload/' + filename, data, err => {
      if (err) {
        reject(err)
      }
      resolve({ message: 'Upload successfully!' })
    })
  })
}

I see a problem when I request a file path from URL http://localhost:2345/upload/test.png It’s 404 Not Found.

Time to implement Inert, I add more routing to serve a public folder, and after that It’s should show an image that upload

This is image title

You can read more about Inert here : https://github.com/hapijs/inert

This is image title
Now, I can view an image via request from URL

Setup NGINX

On production, sometimes its limit your file size, When I use NGINX, I change max file size to 50MB (or whatever you want) in nginx.conf

vi /etc/nginx/nginx.conf
client_max_body_size 50M;