Last active
June 23, 2023 16:38
-
-
Save patrikbego/6b80c6cfaf4f4e6c119560e919409bb2 to your computer and use it in GitHub Desktop.
Native / pure / no-npm file upload REST API
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* 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