How to Build REST Endpoints with Node.js and Dynamsoft Vision SDKs
Two months ago, we published a repository demonstrating how to build a RESTful service with .NET and Dynamsoft Vision SDKs. In this tutorial, the server-side programming language is changed to Node.js. We will go through the steps of creating REST endpoints for scanning documents, decoding barcodes, detecting MRZ, and rectifying documents. The client-side code is reused from the previous open-source project.
This article is Part 3 in a 3-Part Series.
Prerequisites
- Dynamsoft Service: This is a background service used for communicating with document scanners. It can be installed on both Windows and Linux. You can download it from the following links:
- License Key: Dynamic Web TWAIN, Dynamsoft Barcode Reader, Dynamsoft Label Recognizer, and Dynamsoft Document Normalizer require their own license key. Free trial licenses are available here.
Required NPM Packages
{
"dependencies": {
"barcode4nodejs": "^9.6.29",
"body-parser": "^1.20.2",
"cors": "^2.8.5",
"docrectifier4nodejs": "1.0.0",
"docscan4nodejs": "^1.0.1",
"express": "^4.18.2",
"mrz4nodejs": "1.0.2",
"multer": "^1.4.5-lts.1",
"sharp": "^0.32.6"
}
}
- barcode4nodejs: A Node.js
C++
addon for reading 1D and 2D barcodes with the Dynamsoft Barcode Reader. - body-parser: A Node.js body parsing middleware.
- cors: A Node.js package for providing a middleware that can be used to enable
CORS
with various options. - docrectifier4nodejs: A Node.js
C++
addon for rectifying documents with the Dynamsoft Document Normalizer. - docscan4nodejs: A JavaScript library for acquiring documents from scanners with Dynamic Web TWAIN.
- express: A Node.js web application framework.
- mrz4nodejs: A Node.js
C++
addon for detecting MRZ with the Dynamsoft Label Recognizer. - multer: A Node.js middleware for handling
multipart/form-data
, which is primarily used for uploading files. - sharp: A Node.js image processing library.
REST Endpoints Defined in .NET C#
In our previous .NET C# project, the REST endpoints were defined as follows:
Method | Endpoint | Description |
---|---|---|
GET | /dynamsoft/product |
Retrieve the names of all Dynamsoft Vision SDKs. |
GET | /dynamsoft/dwt/getdevices |
Retrieve the device names of connected scanners, including TWAIN, SANE, eSCL, and WIA. |
POST | /dynamsoft/dwt/ScanDocument |
Acquire images from a scanner and return the image data. |
POST | /dynamsoft/dbr/DecodeBarcode |
Upload an image for barcode decoding and return the decoding results. |
POST | /dynamsoft/dlr/DetectMrz |
Upload an image for MRZ detection and return the detection results. |
POST | /dynamsoft/ddn/rectifyDocument |
Upload an image for document rectification and return the rectified image. |
REST Endpoints Implementation in Node.js
Implementing REST endpoints in Node.js is much easier than in .NET C#. Let’s begin with the web server configuration.
const express = require('express');
const cors = require('cors');
const app = express();
const server = http.createServer(app);
app.use(cors());
app.use(express.static('public'));
app.use('/uploads', express.static('uploads'));
const port = process.env.PORT || 3000;
server.listen(port, '0.0.0.0', () => {
host = server.address().address;
console.log(`Server running at http://0.0.0.0:${port}/`);
});
- cors: Enable
CORS
with the default options. - express.static: Serve static files from the
public
folder, which contains the client-side code. Use theuploads
folder for storing uploaded images.
Then initialize the Dynamsoft Vision SDKs with valid license keys.
const barcode4nodejs = require("barcode4nodejs")
const docscan4nodejs = require("docscan4nodejs");
const docrectifier4nodejs = require("docrectifier4nodejs");
const mrz4nodejs = require('mrz4nodejs');
barcode4nodejs.initLicense(
"LICENSE-KEY",
);
mrz4nodejs.initLicense(
"LICENSE-KEY",
);
let mrzScanner = new mrz4nodejs();
let ret = mrzScanner.loadModel(path.dirname(require.resolve('mrz4nodejs')));
docrectifier4nodejs.initLicense(
"LICENSE-KEY",
);
let docRectifier = new docrectifier4nodejs();
docRectifier.setParameters(docrectifier4nodejs.Template.color);
- loadModel: Load the MRZ model that is located in the
node_modules
folder. - setParameters: Set the document rectification template to
color
option.
Configure multer
to save uploaded images in a designated folder.
const multer = require('multer');
const upload = multer({ dest: 'uploads/' });
Based on the endpoint table, the corresponding Node.js code can be written as follows:
-
/dynamsoft/product
.app.get('/dynamsoft/product', (req, res) => { res.send(JSON.stringify(["Dynamic Web TWAIN", "Dynamsoft Barcode Reader", "Dynamsoft Label Recognizer", "Dynamsoft Document Normalizer",])); });
-
/dynamsoft/dwt/getdevices
.app.get('/dynamsoft/dwt/getdevices', (req, res) => { docscan4nodejs.getDevices(dynamsoftService).then((scanners) => { res.send(scanners); }); });
The
scanners
variable is an array of objects, with each object containingdevice
,name
, andtype
properties. For example:[ { device: '{\n' + '\t"deviceInfo" : \n' + '\t{\n' + '\t\t"UUID" : "f8262726-dc64-5cf1-89ab-5e257f2d0f3a",\n' + '\t\t"adminurl" : "http://HP6C02E0BCF77F.local.",\n' + '\t\t"cs" : "binary,color,grayscale",\n' + '\t\t"duplex" : "F",\n' + '\t\t"is" : "platen,adf",\n' + '\t\t"mopria-certified-scan" : "1.2",\n' + '\t\t"name" : "HP LaserJet Pro M329 [BCF77F]",\n' + '\t\t"pdl" : "application/octet-stream,application/pdf,image/jpeg",\n' + '\t\t"representation" : "images/printer.png",\n' + '\t\t"rs" : "eSCL",\n' + '\t\t"service_type" : 3,\n' + '\t\t"txtvers" : "1",\n' + '\t\t"ty" : "HP LaserJet Pro M329",\n' + '\t\t"vers" : "2.63"\n' + '\t},\n' + '\t"deviceType" : 512,\n' + '\t"name" : "SFAgTGFzZXJKZXQgUHJvIE0zMjk="\n' + '}\n', name: 'HP LaserJet Pro M329', type: 512 } ]
-
/dynamsoft/dwt/ScanDocument
.app.post('/dynamsoft/dwt/ScanDocument', async (req, res) => { const json = req.body; let parameters = { license: "LICENSE-KEY", device: json['scan'], }; parameters.config = { IfShowUI: false, PixelType: 2, Resolution: 200, IfFeederEnabled: false, IfDuplexEnabled: false, }; try { let jobId = await docscan4nodejs.scanDocument(dynamsoftService, parameters); let filename = await docscan4nodejs.getImageFile(dynamsoftService, jobId, './uploads'); console.log('Scanned file: ' + filename); res.send(JSON.stringify({ 'image': 'uploads/' + filename })); } catch (err) { console.error(err); return res.status(500).send('An error occurred while processing the image.'); } });
To scan documents, a valid
license
key is required. ThescanDocument
function generates ajobId
, which is used to retrieve the scanned image file. ThegetImageFile
function then saves this image file to the local disk and returns its file name. -
/dynamsoft/dbr/DecodeBarcode
.app.post('/dynamsoft/dbr/DecodeBarcode', upload.single('image'), async (req, res) => { const file = req.file; if (!file) { return res.status(400).send('No file uploaded.'); } try { let result = await barcode4nodejs.decodeFileAsync(file.path, barcode4nodejs.barcodeTypes); console.log(result); res.status(200).send(result); } catch (err) { console.error(err); return res.status(500).send('An error occurred while processing the image.'); } });
The
decodeFileAsync
function returns an array of objects, where each object includes properties for format, value, coordinates, and elapsed time. For example:[ { format: 'QR_CODE', value: 'JOHN DOE\nTR456 43E\nfrom Sydney to Vilnius\n23:40', x1: 991, y1: 309, x2: 1125, y2: 309, x3: 1124, y3: 440, x4: 991, y4: 440, page: 0, time: 31 } ]
-
/dynamsoft/dlr/DetectMrz
.app.post('/dynamsoft/dlr/DetectMrz', upload.single('image'), async (req, res) => { const file = req.file; if (!file) { return res.status(400).send('No file uploaded.'); } try { let result = await mrzScanner.decodeFileAsync(file.path); console.log(result); let output = ""; if (result.length == 2) { output = mrzScanner.parseTwoLines(result[0].text, result[1].text); } else if (result.length == 3) { output = mrzScanner.parseThreeLines(result[0].text, result[1].text, result[2].text); } console.log(output); res.status(200).send(output); } catch (err) { console.error(err); return res.status(500).send('An error occurred while processing the image.'); } });
The
decodeFileAsync
function returns OCR results, typically comprising two or three lines of text. By parsing these strings, we can extract MRZ (Machine Readable Zone) information, such as:{ type: 'PASSPORT (TD-3)', nationality: 'CAN', surname: 'AMAN', givenname: 'RITA TANIA', passportnumber: 'ERE82721 ', issuecountry: 'CAN', birth: '1984-12-07', gender: 'M', expiry: '2024-05-25' }
-
/dynamsoft/ddn/rectifyDocument
.app.post('/dynamsoft/ddn/rectifyDocument', upload.single('image'), async (req, res) => { const file = req.file; if (!file) { return res.status(400).send('No file uploaded.'); } try { let results = await docRectifier.detectFileAsync(file.path); let result = results[0]; result = await docRectifier.normalizeFileAsync(file.path, result['x1'], result['y1'], result['x2'], result['y2'], result['x3'], result['y3'], result['x4'], result['y4']); let data = result['data'] let width = result['width'] let height = result['height'] for (let i = 0; i < data.length; i += 4) { const red = data[i]; const blue = data[i + 2]; data[i] = blue; data[i + 2] = red; } const timestamp = Date.now(); sharp(data, { raw: { width: width, height: height, channels: 4 } }).toFile('uploads/' + timestamp + '.jpeg', (err, info) => { if (err) { console.error('Error:', err); } else { res.send(JSON.stringify({ 'image': 'uploads/' + timestamp + '.jpeg' })); } }); } catch (err) { console.error(err); return res.status(500).send('An error occurred while processing the image.'); } });
The
detectFileAsync
function yields an array of objects, where each object includes the propertiesx1
,y1
,x2
,y2
,x3
,y3
,x4
, andy4
. These properties are coordinates used by thenormalizeFileAsync
function for rectifying the document. ThenormalizeFileAsync
function then returns an image object containing data, width, and height properties. Here,data
is an array representing the image pixels, whilewidth
andheight
specify the image’s dimensions. Thesharp
library encodes and saves the image to the local disk.
Test the REST Endpoints in Web Browser
Open the index.html
file in a web browser. The web page looks like:
Source Code
https://github.com/yushulx/dynamsoft-sdk-webapi-restful-service/tree/main/node