I am trying to set up a minimalistic server using Koa and lowdb; I am also writing everything on typescript and using the experimental feature to work with modules in (nodejs) koa.
I share firstly my .tsconfig
{
"compilerOptions": {
"target": "es2017",
"module": "ESNext",
"lib": [
"es6","DOM"
] ,
"allowJs": true,
"outDir": "build",
"rootDir": "src" ,
"strict": true ,
"noImplicitAny": true,
"moduleResolution": "node",
"esModuleInterop": true,
/* Advanced Options */
"resolveJsonModule": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true
}
Did manage to set up the server but got in a lot of trouble when I wanted to add on Multer and effectively, which library to chose from to handle the incoming data.
on this POST there is a good discussion about the different libraries available at the end I chose to use async-busboy [...] seems to be more up to date, and of course, bring on its own types.
koa is known to treat everything as middleware, so wrappers on async-await are useful!
import multer from '@koa/multer';
import koaStatic from 'koa-static';
import path from 'path';
import asyncBusboy from 'async-busboy';
import multer from '@koa/multer';
import koaStatic from 'koa-static';
import path from 'path';
import asyncBusboy from 'async-busboy';
const router = new Router();
const app = new Koa();
const corsOpt = {
origin: /* process.env.CORS_ALLOW_ORIGIN || */ '*', // this work well to configure origin url in the server
methods: ['GET', 'PUT', 'POST', 'DELETE', 'OPTIONS'], // to works well with web app, OPTIONS is required
allowedHeaders: ['Content-Type', 'Authorization'], // allow json and token in the headers
};
app.use(cors(corsOpt));
app.use(logger());
app.use(koaBody());
app.use(koaStatic(__dirname + './static/uploads'));
const storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, './uploads');
},
filename: function (req, file, cb) {
const uniqueSuffix = Date.now() + '-' + Math.round(Math.random() * 1e9);
cb(null, file.fieldname + '-' + uniqueSuffix + '.jpg');
},
});
const upload = multer({ storage });
app.use(upload.any());
app.use(async function (ctx: KoaContext, next: () => any) {
// ignore non-POSTs
if ('POST' != ctx.method) return await next();
const { files, fields } = await asyncBusboy(ctx.req);
console.log(files);
let err = await upload
.single('file')(ctx as any, next)
.then((res: any) => res)
.catch((err: any) => err);
if (err) {
ctx.body = {
code: 0,
msg: err.message,
};
} else {
ctx.body = {
code: 1,
data: files,
};
}
});
// add a route for uploading multiple files
router.post('/uploader', upload.fields([]), (ctx: KoaContext) => {
console.log('ctx.request.files', ctx.request.files);
console.log('ctx.files', ctx);
console.log('ctx.request.body', ctx.request.body);
ctx.body = 'done';
});
// REST OF CODE ...
app.use(router.routes()).use(router.allowedMethods());
app.listen(4040);
console.log('server running ... http://localhost:4040');
I am still learning, or better said decypher all typescript secrets by doing such experiments. Now I do have a conflict as mutler is doing its own form-data (I assumed by reading from others posts) So far it is a solution to get the file from ctx.req.file via async-await, But I do still struggling with the types.
You can check the whole project here repo
Any help on the types will be great.
Hope it helps to further this discussion now with typescript.