Pact-js: POST body is garbled by VerifyProvider - node.js

I'm running into an odd issue with Pact-js and POST bodies.
The background:
Consumer Side
- I have a NodeJs app which I'm trying to test
- I configured Pact and set up the appropriate framework
- All test run successfully and generate contract
Provider Side:
- Again, I have a NodeJs app which I'm trying to test
- Pact has been set up and framework in place
- When i run the test, all GET requests run successfully, however all POSTs report a fail.
The Issue:
- When I echo out the POST body being passed to the service from Pact (veryifyProvider), i can see that its wrapped the body (JSON) inside another 'Key: value' pairing, where the body i want to parse is the Key and the value is empty. Its also added escape chars ( \ ) to all the double quotes inside the Body.
EX:
{"{\"Account\":\"123\",\"Orbit\":\"5.00\",\"Date\":\"2016-06-22\",\"Client\":\"1234\",\"Spring\":\"1234\"}":""}
When i look in my Pact contract json, everything looks correct. Somewhere between VerifyProvider reading in the JSON and passing it to the REST endpoint, the body is mangled. This only seam to happen during tests, normal invocation works appropriately.
Here is the code I'm using Provider side to execute the Verify:
const verifier = require('pact').Verifier;
const path = require('path');
let contract = path.join(__dirname, 'pactContract.json');
let opts = {
providerBaseUrl: "http://localhost:3001",
pactUrls: [contract],
};
verifier.verifyProvider(opts)
.then((res) => {
console.log('pact veryify complete, !!!');
console.log(res);
process.exit(0);
}).catch((error) => {
console.log(error);
process.exit(1);
});
I'm unable to pull down my exact consumer codebase, but its nearly identical in structure shown here Pact-js.
Any help is VERY much appreciated!

Please check the Content-Type header and ensure it is application/json. This can happen if the service thinks it's matching text messages.

Related

Parsing request body prohibits request signature verification

I'm trying to build a serverless Slackbot using Lambda function. I end up with an error while verifying the Request URL through the Slack event API. #slack/events-api is the dependency that I'm using to capture the slack events.
Here is my code.
const sls = require('serverless-http');
const { createEventAdapter } = require('#slack/events-api');
require('dotenv').config();
const { SLACK_SIGNING_SECRET } = process.env
const slackEvents = createEventAdapter( SLACK_SIGNING_SECRET || '' );
slackEvents.on('message', async event => {
console.log('received!')
});
module.exports.server = sls(slackEvents.requestListener());
This is the error that I'm getting while verifing the request url
Slack Request URL verification
Can someone help me with this?
Just ran into this exact issue, and took a look into http-handler.js in node-slack-events.
All we have to do is store the raw request body as rawBody before serverless-http parses it.
serverless-http lets you transform the request, before it is sent to the app—great opportunity for a fix:
module.exports.handler = serverless(app, {
request(request) {
request.rawBody = request.body;
},
});
I'm not sure how to solve your problem exactly, but I do know what's causing it.
The library you're using, serverless-http parses the JSON body sent by Slack. This causes an error to be thrown, because the slack-api-sdk expects to parse the raw request body itself.
Could you try removing serverless-http and just respond to the API Gateway event?

TypeError [ERR_UNESCAPED_CHARACTERS] Request path contains unescaped characters

I am working on Ubuntu with incoming HTTP request from the following URL:
http://<MY-IP>:3000/v1/projects/list
Description:
The problem is that I get the following error in terminal:
TypeError [ERR_UNESCAPED_CHARACTERS]: Request path contains unescaped characters
at new ClientRequest (_http_client.js:127:13)
at Object.request (https.js:300:10)
at Request.start (/home/dev/grem-api-dev/apiv3/node_modules/request/request.js:751:32)
at Request.end (/home/dev/grem-api-dev/apiv3/node_modules/request/request.js:1512:10)
at end (/home/dev/grem-api-dev/apiv3/node_modules/request/request.js:564:14)
at Immediate._onImmediate (/home/dev/grem-api-dev/apiv3/node_modules/request/request.js:578:7)
at processImmediate(timers.js:632:19)
After this error node process disappears from terminal (but still working and API response is sent properly), though I can't see whether it is working or not (image attached). So the only way to interact with node process is to do something like ps aux | grep node or ps Tand manually kill process.
Assuming the error meaning I've found an appropriate code fragment where the error appears (request.js:751:32). Here it is:
try {
self.req = self.httpModule.request(reqOptions)
} catch (err) {
self.emit('error', err)
return
}
The only solution I've come to is to comment self.emit('error', err) code line, which is obviously far from best practice.
The fact is the same code works on other computers (Ubuntu, Windows) with same components versions and no error occurs. Also API endpoints like http://myIp:3000/v1/community/list work fine on all devices.
Here's my component versions:
npm — 6.5.0,
node — 11.4.0,
request — 2.88.0,
Ubuntu — 16.04 (Windows — 10)
some code fragments if needed (Express Server creation and specific route in ProjectsController):
const app = express();
app.use('/v1/projects/', ProjectsController);
const router = express.Router();
router.post('/list', function(req,res){
//logic
});
I have used axios and the same problem occured.
My problem was solved using encodeURI() or encodeURIComponent() functions.
const URI = 'example.com';
const encodedURI = encodeURI(URI);
PS: For future reader: use require('url').URL to construct a url object and pass it to node-fetch, which will auto escape url for you.
Useful Links: Link1 | Link2
For me, I had some IDE issue that injected some invalid char in a endpoint. Once I used encodeURI, it revealed what char was causing the problem. So I re-wrote the endpoint and it worked.
URL: /v2/users/${user.id}/products
What was being read: /v2/users[some invalid char here]/${user.id}/products
Solution for this issue was finding code fragment that was sending request to other web resource with URL that contained unescaped characters, and then replacing them according to this article https://www.w3schools.com/tags/ref_urlencode.asp. This fragment was executed by condition, that's why only 1 server with specific OS passed through if/else statement.
const request = require('request');
if (...) {}
else {
request.get(...) //source of error
.on('response', function(response) {
//logic
});
}

Node.js - Why does my HTTP GET Request return a 404 when I know the data is there # the URL I am using

I'm still new enough with Node that HTTP requests trip me up. I have checked all the answers to similar questions but none seem to address my issue.
I have been dealt a hand in the Wild of having to go after JSON files in an API. I then parse those JSON files to separate them out into rows that populate a SQL database. The API has one JSON file with an ID of 'keys.json' that looks like this:
{
"keys":["5sM5YLnnNMN_1540338527220.json","5sM5YLnnNMN_1540389571029.json","6tN6ZMooONO_1540389269289.json"]
}
Each array element in the keys property holds the value of one of the JSON data files in the API.
I am having problems getting either type of file returned to me, but I figure if I can learn what is wrong with the way I am trying to get 'keys.json', I can leverage that knowledge to get the individual JSON data files represented in the keys array.
I am using the npm modules 'request' and 'request-promise-native' as follows:
const request = require('request');
const rp = require('request-promise-native');
My URL is constructed with the following elements, as follows (I have used the ... to keep my client anonymous, but other than that it is a direct copy:
let baseURL = 'http://localhost:3000/Users/doug5solas/sandbox/.../server/.quizzes/'; // this is the development value only
let keysID = 'keys.json';
Clearly the localhost aspect will have to go away when we deploy but I am just testing now.
Here is my HTTP call:
let options = {
method: 'GET',
uri: baseURL + keysID,
headers: {
'User-Agent': 'Request-Promise'
},
json: true // Automatically parses the JSON string in the response
};
rp(options)
.then(function (res) {
jsonKeysList = res.keys;
console.log('Fetched', jsonKeysList);
})
.catch(function (err) {
// API call failed
let errMessage = err.options.uri + ' ' + err.statusCode + ' Not Found';
console.log(errMessage);
return errMessage;
});
Here is my console output:
http://localhost:3000/Users/doug5solas/sandbox/.../server/.quizzes/keys.json 404 Not Found
It is clear to me that the .catch() clause is being taken and not the .then() clause. But I do not know why that is because the data is there at that spot. I know it is because I placed it there manually.
Thanks to #Kevin B for the tip regarding serving of static files. I revamped the logic using express.static and served the file using that capability and everything worked as expected.

Get headers from a request using Nodejs

I'd like to get the headers form a request (ex: status code, content-lenght, content-type...). My code :
options = {
method:'HEAD'
host:"123.30.xxx.xxx"
port:80
}
http.request(options,(res)->
res.send JSON.stringify(res.headers)
)
but this is not working
Please help me :(
Your JSON is not valid and it appears that you are not instantiating options as a variable prior to it's use. ev0lutions code resolves these issues as well as ending the request.
For info on how to create valid JSON check out this tutorial:
http://www.w3schools.com/json/
You need to call .end() on your http.request() object in order to make your request - see the docs:
With http.request() one must always call req.end() to signify that you're done with the request - even if there is no data being written to the request body.
For example:
var options = {
method:"HEAD",
host:"google.com",
port:80
};
var req = http.request(options,function(res) {
console.log(JSON.stringify(res.headers));
});
req.end();
Another issue in your code is that res doesn't have a .send() method - if you're referring to another res variable (for example, containing the code that you have posted) then your variables will be conflicting. If not, you should double check what you're trying to do here.

Compound JS - Using POST method in API

I am working on CompoundJS and i would like to create an api for my mobile application.
Below is the expected output
1) An api localhost:3000/test
2) Some data has tobe POSTED to this api say number: 1
3) The API should respond with the number posted, result should be = 1
I tried the below
1) Created a controller say test_controller.js
2) Added an action showtest with below code
action(function showtest(req, res) {
console.log(req.body);
});
3) Added router config like
map.post('test', 'test#showtest')
When i posted to the url localhost:3000/test, it shows
like 200 successful, but in Firebug console the response shows error.
What am i doing wrong? is there anything as like Rails render :text => "hello"
we can use it for CompoundJS.
Your action isn't correct. Try this:
action('showtest', function() {
for (var key in req.body)
{
send(key.toString());
break;
}
});
Express used to expose a .rawBody property on the request object, which would contain the raw data posted, but as of Express 3.x this functionality has been removed. The for loop in the above code will return the first key of the req.body object (which, when the data POST'ed is just a single number, will be that number).

Resources