Skip to content

Instantly share code, notes, and snippets.

@patrikbego
Last active June 23, 2023 16:38
Show Gist options
  • Star 6 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save patrikbego/6b80c6cfaf4f4e6c119560e919409bb2 to your computer and use it in GitHub Desktop.
Save patrikbego/6b80c6cfaf4f4e6c119560e919409bb2 to your computer and use it in GitHub Desktop.
Native / pure / no-npm file upload REST API
/**
* This is native /pure /no-npm node.js file uploader.
*
* CLIENT FUNCTION: export function uploadFile(file) {
* fetch("http://localhost:8080/sys/upload", {
* method: 'POST',
* headers: { "Content-Type": "multipart/form-data;"},
* body: file }).then(response => response.json()
* ).then(
* success => console.log(success)
* ).catch(
* error => console.log(error)
* );
* }
*
*/
const http = require('http');
const url = require('url');
const fs = require('fs');
const route = {};
// handler for /hello endpoint
route.hello = function(data, callback) {
callback(200, {res: 'Hello World'});
};
// handler for admin/env endpoint
route.env = function(data, callback) {
callback(200, (function() {
if (process.env.PROD !== undefined) {
return {res: 'PROD'};
} else if (process.env.DEV !== undefined) {
return {res: 'DEV'};
} else {
return {res: 'LOCALHOST'};
}
})());
};
// handler for sys/upload endpoint
route.upload = function(data, callback) {
console.log('Upload started');
saveFile(data).then(
(result) => {
callback(200, {res: 'File successfully uploaded: ' + result});
console.log('Upload finished');
},
(error) => {
callback(500, {res: 'File was not uploaded: ' + error});
console.log('Upload failed');
},
);
};
// default handler
route.notFound = function(data, callback) {
callback(404);
};
// path router
const router = function(path) {
switch (path) {
case 'hello':
return route.hello;
case 'sys/env':
return route.env;
case 'sys/upload':
return route.upload;
default:
return route.notFound;
}
};
// hardcoded multipart parser roughly based on https://www.w3.org/Protocols/rfc1341/7_2_Multipart.html
function multipartParser(body) {
body = body.split('\r\n');
const jsonBody = {};
for (let i = 0; i < body.length; i++) {
const arrayPart = body[i];
if (arrayPart.includes('name=')) {
const fieldName = arrayPart.substring(
arrayPart.indexOf('name=') + 6, arrayPart.lastIndexOf('"'));
jsonBody[fieldName] = body[i + 2];
}
}
return {body, jsonBody};
}
function saveFile(data) {
const saveName = data.body.originalFileName;
const base64Data = data.body.file.replace(/^data:[a-z]*\/[a-z]*;base64/, '');
return new Promise(function(resolve, reject) {
fs.writeFile(`./uploaded_base64Data_${saveName}`, base64Data, 'base64',
function(err) {
if (err) reject(err);
else resolve(data);
}
);
});
}
const server = http.createServer(function(req, res) {
// enable cors
res.setHeader('Access-Control-Allow-Origin', 'http://localhost:3000');
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE, HEAD');
res.setHeader('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept');
res.setHeader('Access-Control-Allow-Credentials', 'true');
// parse the requested url
const requestUrl = url.parse(req.url, true);
console.log('requestUrl: ' + requestUrl);
// parse the trimmed path which we will use in the router
const routePath = requestUrl.pathname.replace(/^\/+|\/+$/g, '');
console.log('routePath: ' + routePath);
let body = [];
// push the chunked data into the body array
req.on('data', function(chunk) { // https://developer.mozilla.org/en-US/docs/Web/API/Streams_API https://nodejs.org/api/stream.html
body.push(chunk);
});
// handle the data coming from request
req.on('end', function() {
const routeHandler = router(routePath);
body = Buffer.concat(body).toString();
const __ret = multipartParser(body);
const jsonBody = __ret.jsonBody;
const data = {
'routePath': routePath,
'query': requestUrl.query,
'method': req.method,
'headers': req.headers,
'body': jsonBody,
};
routeHandler(data, function(statusCode, payload) {
statusCode = typeof (statusCode) === 'number' ? statusCode : 200;
payload = typeof (payload) === 'object' ? payload : {};
res.writeHead(statusCode);
res.end(payload.res);
console.log('Response: ', statusCode, payload.res);
});
});
});
server.listen(8080, function() {
console.log('Server started on port 8080!');
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment