Simple file uploads with Koa and FormData

Stephen Watkins
2 min readJun 12, 2018

--

If your experience with uploading files to S3 is anything like mine, you’ll run into a throng of information void of succinct, easy-to-digest code. So, I’ve put together a step-by-step guide that takes you from the browser to S3 using Koa and FormData. Let’s jump in.

Note that this guide will work for any S3 compatible service. That means if you’re using DigitalOcean Spaces, for example, the code also applies to you.

Firstly, we’ll setup our Koa server to send files to S3. This assumes that you already have a node project setup.

  1. Install libraries:
yarn add koa koa-router koa-body aws-sdk// ornpm i koa koa-router koa-body aws-sdk

2. Write a POST route to handle uploads:

const Koa = require("koa");
const koaRouter = require("koa-router");
const koaBody = require("koa-body");
const router = new koaRouter();
router.post("/upload", async ctx => {
const file = ctx.request.files.file;
const { key, url } = await uploadFile({
fileName: file.name,
filePath: file.path,
fileType: file.type,
});
ctx.body = { key, url };
});
// We enable multipart body parsing
app.use(koaBody({ multipart: true }));
app.use(router.routes());
app.use(router.allowedMethods());
app.listen(process.env.PORT);

3. Implement the uploadFile method:

const aws = require("aws-sdk");
const fs = require("fs");

const uploadFile = async ({ fileName, filePath, fileType }) => {
return new Promise((resolve, reject) => {
aws.config.update({
region: "nyc3",
// You'll need your service's access keys here
accessKeyId: "",
secretAccessKey: "",
});

const s3 = new aws.S3({
apiVersion: "2006-03-01",
// If you want to specify a different endpoint, such as using DigitalOcean spaces
// endpoint: new aws.Endpoint("nyc3.digitaloceanspaces.com"),
});

const stream = fs.createReadStream(filePath);
stream.on("error", function(err) {
reject(err);
});

s3.upload(
{
ACL: "public-read",
// You'll input your bucket name here
Bucket: "bucket-name",
Body: stream,
Key: fileName,
ContentType: fileType,
},
function(err, data) {
if (err) {
reject(err);
} else if (data) {
resolve({ key: data.Key, url: data.Location });
}
}
);
});
};

module.exports = { uploadFile };

Finally, we’ll implement the browser portion.

  1. Include an <input type="file" /> on your page.
  2. Write an onchange handler that sends the file to your server:
// Select your file input
const fileInput = document.querySelector("input[type='file']");
// Add your onchange handler
imageUpload.onchange = async e => {
const files = e.target.files;
const fileToUpload = files[0];

let data = new FormData();
data.append("file", fileToUpload);

// Send as multipart/form-data
// Ensure the URL points to your server
const response = await fetch("/upload", {
method: "POST",
body: data,
});
const { url } = await response.json();

// Now you have a URL of the file uploaded to S3
};

That’s it! Eventually, you’ll want to ensure you’re handling errors in the upload process and validating file constraints.

I hope this helps others struggling to find a simple example of uploading files, complete from browser to server.

--

--