How to map SOAP request with SOAP response using node-soap - node.js

I use node-soap to manage SOAP requests/responses on server side. I'm using server.log function to log requests and responses and I need to somehow map them (connect) to know which request caused a certain response.
See the code sample:
function log(type, data) {
let logId = '';
if (type === 'received') {
// On received I need to generate logId
logId = generateLogId();
console.log(logId, data);
}
if (type === 'replied') {
// On replied I need to get the logId that was generated on the matching request
logId = getLogId();
console.log(logId, data);
}
}
I've tried using node's continuation-local-storage, but without much success.
Help me, Obi-Wan Kenobi. You're my only hope.

Related

Node.js Soap method params parsed as string instead of related object

I'm using node-soap to consume a WebService. I've used this library and consumed this service many times before, but this time I'm having the following situation.
I create the client using the WSDL that contains the methods, inputs etc:
const soap = require("soap");
const url = "https://servintp.latinoseguros.com.mx:8071/wsCotizadorAutos/cotizador/CotizadorLatino.svc?wsdl";
soap.createClient(url, {}, (error, client) => {
if (error) {
callback(error);
} else {
const describe = client.describe()["CotizadorLatino"]["BasicHttpBinding_ICotizadorLatino"];
console.log(describe["ObtenerMarcas"])
}
});
The request is successful and the client is created, but when I describe the method "ObtenerMarcas" I receive the following object:
{
input: { datos: 'q17:DatosRequeridos' },
output: { ObtenerMarcasResult: 'q18:ListMarca' }
}
Whose only input param shows as only a String, while it should be an object whith different objects and attributes.
When using Soap Client and inputing the exact same WSDL endpoint, the method is described as it should, with all the children and attributes that are expected to be passed:
Soap Client Screenshot
Which makes me believe that this has something to do with the client configuration or probably something very basic that I'm not taking into account.
Can anybody point me on what I'm doing wrong?
Thanks!

How can I get an express server to send the data retrieved by a separate provider to a client?

I'm currently writing a small program in Node.js for an express server. I am using providers to facilitate the separation of concerns. What I'm having trouble with is figuring out how to send a return value from the provider function back to the express server and then to the client. I'm probably missing something with the asynchronous code but can't seem to figure out what. I'd be grateful if you could guide me in the right direction! Sorry if this is an obvious question, I'm very new to programming.
This is the code skeleton for the main.js:
server.get("/someurl*", (req, res) => {
let name = req.query.name;
let id = req.query.id;
if (
(isValid(name) == true) &&
(isValid(id) == true)
) {
let provider = new getSomething();
provider.getMethod(id);
res.send(provider.getMethod(id));
};
});
This is the code skeleton for provider.js:
class getSomething extends abstractClass {
getMethod(id) {
this.id = id;
// Acquiring data from database based on id
…
if (err)
return (‘error’);
return data;
};
};
What I do not understand is how can I send the data back to the express server (main.js) and then send that data back to the client with res.send. The way I'm doing it above doesn't work as it returns an undefined value. I cannot do res.send directly from the provider as it should only be responsible for retrieving data from the database and the server instance is defined in main.js.
Thank you very much in advance!
In your provider class I would ammend the getMethod to be something more like this:
getMethod(id) {
this.id = id;
//do something. update this.data
if (err) this.error = err;
//optional for method chaining: return this;
}
Class methods can be used to modify the properties of the class, which you can then send to the client.
then in your endpoint:
server.get(“/someurl*”, (req, res) => {
const name = req.query.name; //use consts for values that you dont want to change
const id = req.query.id;
if ((isValid(name) == true) && (isValid(id) == true)) {
const provider = new getSomething();
provider.getMethod(id);
if (provider.error) return res.status(500).json({error: provider.error});
return res.status(200).json({data: provider.data});
};
return res.status(500).error({error: 'query data not valid'});
});
this is extracting the data you require from the query object, then if everything is valid (im asuming some other function you have for validation) will instantiate a new instance of your class, run the method, and if theres an error send this back to the client otherwise send back data to the client.
If the data is not valid it also sends back a response to the client. In any case you want to send something back to the client.

How to use the full request URL in AWS Lambda to execute logic only on certain pages

I have a website running on www.mywebsite.com. The files are hosted in an S3 bucket in combination with cloudFront. Recently, I have added a new part to the site, which is supposed to be only for private access, so I wanted to put some form of protection on there. The rest of the site, however, should remain public. My goal is for the site to be accessible for everyone, but as soon as someone gets to the new part, they should not see any source files, and be prompted for a username/password combination.
The URL of the new part would be for example www.mywebsite.com/private/index.html ,...
I found that an AWS Lambda function (with node.js) is good for this, and it kind of works. I have managed to authenticate everything in the entire website, but I can't figure out how to get it to work on only the pages that contain for example '/private/*' in the full URL name. The lambda function I wrote looks like this:
'use strict';
exports.handler = (event, context, callback) => {
// Get request and request headers
const request = event.Records[0].cf.request;
const headers = request.headers;
if (!request.uri.toLowerCase().indexOf("/private/") > -1) {
// Continue request processing if authentication passed
callback(null, request);
return;
}
// Configure authentication
const authUser = 'USER';
const authPass = 'PASS';
// Construct the Basic Auth string
const authString = 'Basic ' + new Buffer(authUser + ':' + authPass).toString('base64');
// Require Basic authentication
if (typeof headers.authorization == 'undefined' || headers.authorization[0].value != authString) {
const body = 'Unauthorized';
const response = {
status: '401',
statusDescription: 'Unauthorized',
body: body,
headers: {
'www-authenticate': [{key: 'WWW-Authenticate', value:'Basic'}]
},
};
callback(null, response);
}
// Continue request processing if authentication passed
callback(null, request);
};
The part that doesn't work is the following part:
if (!request.uri.toLowerCase().indexOf("/private/") > -1) {
// Continue request processing if authentication passed
callback(null, request);
return;
}
My guess is that the request.uri does not contain what I expected it to contain, but I can't seem to figure out what does contain what I need.
My guess is that the request.uri does not contain what I expected it to contain, but I can't seem to figure out what does contain what I need.
If you're using a Lambda#Edge function (appears you are). Then you can view the Request Event structure here: https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/lambda-event-structure.html#lambda-event-structure-request
You can see the actual value of the request URI field by using console.log and checking the respective logs in Cloudwatch.
The problem might be this line:
if (!request.uri.toLowerCase().indexOf("/private/") > -1) {
If you're strictly looking to check if a JavaScript string contains another string in it, you probably want to do this instead:
if (!request.uri.toLowerCase().indexOf("/private/") !== -1) {
Or better yet, using more modern JS:
if (!request.uri.toLowerCase().includes("/private/")) {

How to get body content from request in mobile service in Azure

I crate a mobile service and also a custom api for that in Azure. I use fiddler to send request and do some basic and simple testing.
At Azure side, I create a custom api for my mobile service. Let say the name is ExampleCustomApi. And in the code I have
exports.put = function(request, response) {
var tags = request.parameters.tags;
...
...
}
At fiddler side, I set http method to "PUT" and the url to my custom api.
Then I set a request body to { "tags": "tag1" }.
When I execute the request in fiddler, I receive 500 back. The log in Azure's mobile service says that parameters is undefined.
My question, then, is how to get the request body at the server side. I look at the document of request object, it seems to me that parameters is the one I should use, but it doesn't work.
request is an object in express.js library.
This is the documentation from MSDN http://msdn.microsoft.com/library/azure/jj554218.aspx
the documentation from express.js http://expressjs.com/api.html#req.body
And I can use request.body to get the body content.
After many attempts we cracked getting the content from a weburl. Hope this helps :) Jsonbody would hold your page content. This is a copy where we pulled json from one of our API's
var message = "try";
var jsonBody = "";
var request = require('request');
request.get({
url: "https://superduperwebaddress.com/api/pull"},
function(error,response,body){
if(!error)
{
var mybody = JSON.parse(body);
jsonBody = mybody;
console.warn("we are here well");
}else{
console.error(error);
}
}
);

Node.js SOAP Call with Complex Types

I am currently attempting to use node-soap (https://github.com/milewise/node-soap) to make calls to Authorize.net's SOAP server. However, I cannot seem to get my client code pass the proper parameters. I know that the function is calling the server since I get a server error response.
When I examine the WSDL, I notice that the server call requires ComplexType parameters. Is there a way to create the ComplexTypes that I need or can I just use Javascript objects? Here is my current code:
var soap = require('soap');
var url = 'https://api.authorize.net/soap/v1/Service.asmx?WSDL';
soap.createClient(url, function(err, client) {
var args = {
merchantAuthentication: {
name: '285tUPuS',
transactionKey: '58JKJ4T95uee75wd'
}
};
client.Service.ServiceSoap12.GetTransactionDetails(args,
function(err, result) {
if (err) {
console.log(err);
} else {
console.log(result.GetTransactionDetailsResult[0].messages);
}
});
});
The node-soap module is converting your JavaScript object to XML before sending the transaction to the server. It wraps the request in an xml element as outlined by the wsdl. Here is an example of what might be produced by node-soap when passing the object you provided (important to note the outer element is created by the node-soap module according to the wsdl):
This example is using the wsdl for the CyberSource API
<data:requestMessage xmlns:data="urn:schemas-cybersource-com:transaction-data-1.93" xmlns="urn:schemas-cybersource-com:transaction-data-1.93">
<data:merchantAuthentication>
<data:name>285tUPuS</data:name>
<data:transactionKey>58JKJ4T95uee75wd</data:transactionKey>
</data:merchantAuthentication>
</data:requestMessage>
Also, I don’t know exactly how the Authorize.net api works, but it sounds like you might want to check out using username token authentication if necessary:
client.setSecurity(new soap.WSSecurity('username’, ‘password’));

Resources