简体   繁体   中英

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!

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.

Code your express application as usual

var soap = require('soap');
var express = require('express');

var app = express();

app.use('/', express.static(__dirname + '/public'));
app.use('/node_modules', express.static(__dirname + '/node_modules'));

/* other express part */

but don't do app.listen

Build your server like this

var server = require('http').createServer(app);

Code soap part and terminate like this

soap.listen(server, '/wsdl', MyService, xml);
server.listen(8080);

If you want also want websocket use server too

var io = require('socket.io')(server);
/* io part */

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM