First of all we need node js server installed in our server.
Second of all we need to create the microservice server. We need to use typescript.
We take quick look here: https://developer.okta.com/blog/2018/11/15/node-express-typescript
We set up the project to use typescript: npm install --save-dev typescript
We install tslint: npm install --save-dev tslint
We install express: npm install express
The first running code looks like this:
import express from "express"; const app = express(); const port = 8080; // default port to listen // define a route handler for the default home page app.get("/", (req, res) => { res.send("Hello world!"); }); // start the Express server app.listen(port, () => { // tslint:disable-next-line:no-console console.log(`server started at http://localhost:${port}`); });
We start the server: npm run start
If we call http://localhost:8080/ with Postman we get Hello World.
For the image pth we add this piece of code:
// define a route handler for the image processing app.get("/image/:imageName/:imageResolution", (req, res) => { res.send(`image named ${req.params.imageName} and resolution ${req.params.imageResolution}`); });
We call it with Postman:
For caching we might use info from here:
https://medium.com/the-node-js-collection/simple-server-side-cache-for-express-js-with-node-js-45ff296ca0f0
Cache will not be used right now. We will focus on image serving and image resizing.
For image resizing we use this article:
https://gabrieleromanato.name/nodejs-resize-images-as-thumbnails-on-the-fly-in-expressjs
This means that we are using imagemagick and graphicsmagick libraries.
We install gm npm install gm
Examples of usage here: https://www.npmjs.com/package/gm
Maybe use this for streaming and caching https://stackoverflow.com/questions/39232296/node-js-cache-image-to-filesystem-and-pipe-image-to-response?rq=1
We try using stream for streaming: npm install stream
We use path for file name manipulation
const fileExtension = path.extname(fileAbsolutePath); const fileName = path.basename(fileAbsolutePath).replace(fileExtension, "");
GM not working, mabe use sharp: https://github.com/lovell/sharp
We uninstall the old packages gm and imagemagick.
We install new sharp package npm install sharp
We use sharp to resize the image, save it to the folder and send it to the user.
sharp(fileAbsolutePath).resize(100, 100).toFile(resizeFileAbsolutePath, (err, info) => { if (err) { // tslint:disable-next-line:no-console console.error(err); res.status(404).send({ error: err }); } else { res.status(200).sendFile(resizeFileAbsolutePath); } });
We finally get a barely working image processor with about 30 lines of code.
// define a route handler for the image processing app.get("/image/:imageName/:imageResolution", (req, res) => { // res.send(`image named ${req.params.imageName} and resolution ${req.params.imageResolution}`); const imageName = req.params.imageName; const imageResolution = req.params.imageResolution; const imagesFolder = __dirname + `/images/`; const fileAbsolutePath = imagesFolder + `${imageName}`; const fileExists = fs.existsSync(fileAbsolutePath); if (fileExists) { // file with requested resolution already exists const resolutionExists: boolean = false; // to see how to organize file and check for different resolutions if (resolutionExists) {// If the image does exist on the file system, then stream the image to the response object fs.createReadStream(fileAbsolutePath).pipe(res); } else { // file with required resolution does not exist, we must resize it const fileExtension = path.extname(fileAbsolutePath); const fileName = path.basename(fileAbsolutePath).replace(fileExtension, ""); const resizedFileName = `${fileName}_100x100${fileExtension}`; const resizeFileAbsolutePath = imagesFolder + `${resizedFileName}`; sharp(fileAbsolutePath).resize(100, 100).toFile(resizeFileAbsolutePath, (err, info) => { if (err) { // tslint:disable-next-line:no-console console.error(err); res.status(404).send({ error: err }); } else { res.status(200).sendFile(resizeFileAbsolutePath); } }); } } else { res.status(404).send({ error: `image named ${imageName} and resolution ${imageResolution} was not found` }); } });
If we call the url with POSTMAN we get the image created on the server and the image served. (24ms)