Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SOAP server with Express.js

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!

like image 794
newbie Avatar asked Dec 10 '22 20:12

newbie


2 Answers

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

enter image description here

or by SoapUI

enter image description here

Check posted wsdl can be retrievable by browser

enter image description here

like image 85
Steve Park Avatar answered Dec 31 '22 01:12

Steve Park


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.

like image 24
prasun Avatar answered Dec 31 '22 03:12

prasun