I have created a simple SOAP server using node-soap which is currently serving the requests from a SOAP client. Now the requirement is to serve both incoming REST and SOAP requests from different clients in future. My question is can I achieve this by using a single Express app(Using the Express.js framework)? I am new to this, so any help would be appreciated. Thanks in advance!
I think prasun gave good example already, but want to share mine with more detail. I used express and soap, but use http / https for creating server instead of using express
First, below is project structure and I modularized routes folder for RESTful endpoint routers and services folder for Soap WebService endpoints
/config/index.js
/routes/index.js
/services/wsdl/poservice.wsdl
/services/poservice.js
app.js
server.js
create router by express and build endpoint for GET request for root ('/') context path
[ routers/index.js ]
var express = require('express');
var router = express.Router();
router.get('/', function(req, res, next) {
res.setHeader('Content-Type', 'application/json');
res.send(JSON.stringify({"data": "some data"}));
});
module.exports = router;
Build main routing map on app.js
[ app.js ]
var express = require('express');
var bodyParser = require('body-parser');
var indexRouter = require('./routes/index');
var app = express();
app.use(bodyParser.raw({type: function(){return true;}, limit: '5mb'}));
app.use('/', indexRouter);
module.exports = app;
Set service, port and operation object and also publish wsdl from filepath (./services/wsdl/PurchaseOrderServiceV2.wsdl)
[ services/poservice.js ]
var fs = require('fs');
var path = require('path');
var poServiceXml = fs.readFileSync(path.join(path.join(__dirname, 'wsdl'), 'PurchaseOrderServiceV2.wsdl'), 'utf8');
var poService = {
PurchaseOrderService: {
PurchaseOrderServiceSoapHttpPort: {
getPurchaseOrder: function(args) {
console.log(args);
return {
name: args.name
};
}
}
}
};
module.exports = {
service: poService,
xml: poServiceXml
};
This service, port and operation setup is based on the wsdl. Below is snipped wsdl service, port and operation definition
[ services/wsdl/PurchaseOrderServiceV2.wsdl ]
<wsdl:operation name="getPurchaseOrder">
<wsdl:input message="tns:PurchaseOrderService_getPurchaseOrder"/>
<wsdl:output message="tns:PurchaseOrderService_getPurchaseOrderResponse"/>
<wsdl:fault name="ServiceException" message="errors:ServiceException"/>
</wsdl:operation>
:
<wsdl:service name="PurchaseOrderService">
<wsdl:port name="PurchaseOrderServiceSoapHttpPort" binding="tns:PurchaseOrderServiceSoapHttp">
<soap:address location="https://efqf-test.prc.us6.oraclecloud.com:443/prcPoEditDocumentOrder/PurchaseOrderServiceV2"/>
:
Now create server and run RESTful and Soap endpoints
[ server.js ]
var fs = require('fs');
var config = require('./config');
var app = require('./app');
var debug = require('debug')('po-service:server');
var http = require('http');
var https = require('https');
var soap = require('soap');
const poService = require('./services/poservice');
/**
* Get port from environment and store in Express.
*/
var port = normalizePort(process.env.PORT || config.get('app.port'));
app.set('port', port);
/**
* Create HTTP server or HTTPS server
*/
var server = http.createServer(app);
if(config.get('app.https')) {
server = https.createServer({
key: fs.readFileSync(config.get('app.serverkey')),
cert: fs.readFileSync(config.get('app.servercert'))
}, app);
}
/**
* Listen on provided port, on all network interfaces.
*/
function startServer() {
server.listen(port);
server.on('error', onError);
server.on('listening', onListening);
soap.listen(server, '/prcPoEditDocumentOrder/PurchaseOrderServiceV2', poService.service, poService.xml);
}
if(!module.parent) {
// Start server if file is run directly
startServer();
} else {
// Export server, if file is referenced via cluster
module.exports = startServer;
}
/**
* Normalize a port into a number, string, or false.
*/
function normalizePort(val) {
var port = parseInt(val, 10);
if (isNaN(port)) {
// named pipe
return val;
}
if (port >= 0) {
// port number
return port;
}
return false;
}
/**
* Event listener for HTTP server "error" event.
*/
function onError(error) {
if (error.syscall !== 'listen') {
throw error;
}
var bind = typeof port === 'string'
? 'Pipe ' + port
: 'Port ' + port;
// handle specific listen errors with friendly messages
switch (error.code) {
case 'EACCES':
console.error(bind + ' requires elevated privileges');
process.exit(1);
break;
case 'EADDRINUSE':
console.error(bind + ' is already in use');
process.exit(1);
break;
default:
throw error;
}
}
/**
* Event listener for HTTP server "listening" event.
*/
function onListening() {
var addr = server.address();
var bind = typeof addr === 'string'
? 'pipe ' + addr
: 'port ' + addr.port;
debug('Listening on ' + bind);
}
For configuration, I have config module
[ config/index.js ]
var PropertiesReader = require('properties-reader');
var config = new PropertiesReader('app.properties');
module.exports = config;
and below is configuration file
[ app.properties ]
[app]
hostname = localhost
port = 8080
https = false
serverkey = /path/to/signed.key
servercert = /path/to/signed.crt
Now verify RESTful endpoint
$ curl http://localhost:8080/
{"data":"some data"}
Verify Soap endpoint by Advanced REST client
or by SoapUI
Check posted wsdl can be retrievable by browser
From the pull#872 it supports express
server out of the box.
expressServer = express();
server = expressServer.listen(51515, function(){
var soapServer = soap.listen(expressServer, '/SayHello', service, wsdl);
});
where \sayHello
is the route on which you want to handle wsdl
requests.
Also, note that it will support all the middleware and body parsers as well.
For more details on syntax you can see the tests included in this pull request.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With