AWS API Gateway get request query params with '+' sign not working - api

I have implemented GET request in API Gateway and its working fine but today I get a name in which '+' sign is there so does anyone has any idea that .../score?team=name+with+sign is not working where as ..../score?team-with-dashes works perfectly fine.
Content type of request is application/json.
Here is Body Mapping Template (application/json)
{
"body" : $input.json('$'),
"headers": {
#foreach($header in $input.params().header.keySet())
"$header": "$util.escapeJavaScript($input.params().header.get($header))" #if($foreach.hasNext),#end
#end
},
"method": "$context.httpMethod",
"params": {
#foreach($param in $input.params().path.keySet())
"$param": "$util.escapeJavaScript($input.params().path.get($param))" #if($foreach.hasNext),#end
#end
},
"query": {
#foreach($queryParam in $input.params().querystring.keySet())
"$queryParam": "$util.escapeJavaScript($input.params().querystring.get($queryParam))" #if($foreach.hasNext),#end
#end
}
}
Is this something related to URL Query String Parameters or something else?

The + character in a query parameter is a special character. It is the replacement character for a space character.
So if the client intends to send .../score?team=name with spaces, then the client may encode the URL as .../score?team=name+with+spaces. It may also encode it as .../score?team=name%20with%20spaces.
This means that on the server-side, the parameter should be unencoded with the + converted back to spaces.
If you truely want a + character in your query parameter value, then you must encode it as %2B, such as .../score?team=name%2Bwith%2Bsign.

Related

How to pass xml as Json attribue in postman

I am trying to write a really simple test in Postman. I have two URL and first url get some XML file and then store this in Postman varible as a pre script section.
After that second URL uses this response and send a another request for Post.
but after getting result from xml successfully , somehow postman does not pass this request and gives 400.
pm.environment.set('RandomNumber', "cot"+Math.floor(Math.random() * 1000));
pm.sendRequest("https://test/metadata.xml", function (err, response) {
pm.environment.set('**RandomURLText**', response.text());
});
RandomURLText varible store the value of first request.
Second request body params looks like below code .
**{
"idPType": "Test",
"dontShowProgress": true,
"dontIncludeRequestedAuthnContext": true,
"nameIDFormat": "run:SAML:2.0:nameid-format:transient",
"sigAlg": "http://www.w3.org/2001/04/xmldsig-more#rsa-a",
"metadata": {
"idpXml": "{{RandomURLText}}"
}
}**
is there any function postman who can transform this xml response data. Because second request say 400 when it add xml type data. But when I just replaced this responsetext to hello then its works.
That's means something is wrong in xml type data , may be escape chars.
could someone help me on this?
Thanks
found answer myself, its working.
Just need to parse into string and need to removed quote from body.
pm.environment.set('RandomURLText', JSON.stringify(response.text()));
**{
"idPType": "Test",
"dontShowProgress": true,
"dontIncludeRequestedAuthnContext": true,
"nameIDFormat": "run:SAML:2.0:nameid-format:transient",
"sigAlg": "http://www.w3.org/2001/04/xmldsig-more#rsa-a",
"metadata": {
"idpXml": {{RandomURLText}}
}
}**
Thanks

Parse string into JSON

I have an array of objects $arr and an object has a property named as jsonData which contains json data in a string, how to parse that string to actual JSON object and retrieve lets say value for key name? I tried this:
#foreach ($obj in $arr)
#set ($jsonData = "#evaluate(${obj.jsonData})")
$jsonData.get("name") ## <-- not working
#end
If anyone using velocity in AWS API Gateway ends up here, you can use AWS'
$util.parseJson() to covert a string to JSON.
Make sure you note if your string is using single or double quotes. You may need to use $util.escapeJavaScipt.replaceAll() before parsing the string.
Fixed it like this:
#foreach ($obj in $arr)
#set( $jsonData = '#set( $jsonData = ' + $obj.jsonData + ' )' )
#evaluate ($jsonData)
$jsonData.get("name") ##<-- works now
#end
I was using velocity 1.7
This is mainly AWS lambda (in python) response template related.. so.. if you want to return custom response code with json it is easy to return JSON in node js but when it comes to python as per i know, we cant raise dict as a value. So.. this may help. If you are doing like..
raise Exception({"responseCode": 400, "response": "missing :\"recipientCount\""})
It will throw exception in errorMessage key and value as a string.
To overcome this..
Add response code 400 in Method Response
regExp in Integration Response :
.*'responseCode': 400.*
Add Body Mapping Template as application/json:
$util.escapeJavaScript( $input.path('$.errorMessage')).replaceAll("\\'",'\"')
Make sure you are not using single quotes in value in exception string.
Wrong:
raise Exception({"responseCode": 400, "response": "missing :'recipientCount'"})
Right:
raise Exception({"responseCode": 400, "response": "missing :\"recipientCount\""})
I know it is not best solution... but this is the only solution i have found. Feel free if you have better solution.

How to pass dynamic json request body in postman

I have a POST request where i need to pass some parameters dynamically since my code is checking for a duplicate entry. I tried writing a pre request script and then setting the global variables and tried to access it in my request. It is not working. PFB, the details
Pre-request Script
postman.setGlobalVariable("firstname", (text + parseInt(Math.random()*10000)).toString());
postman.setGlobalVariable("lastname", text + parseInt(Math.random()*10000));
Body
{
"request":
{
"firstName":"{{firstname}}",
"middleName":"mani",
"lastName":"{{lastname}}"
}
}
Here firstName is getting passed as {{firstname}} instead of random string.
You ca do it by adding
var rnd = Math.floor((Math.random() * 10000) + 1);
postman.setEnvironmentVariable("firstname", "fname"+rnd);
postman.setEnvironmentVariable("lastname", "lname"+rnd);
in the Pre-request Script section.
And then adding
{
"firstName":"{{firstname}}",
"middleName":"mani",
"lastName":"{{lastname}}"
}
in the body.
I tried it in both Postman and Newman and is working perfectly generating a random first name and last name.
{
"request": {
"firstName":"{{$randomInt}}",
"middleName":"mani",
"lastName":"{{$randomInt}}"
}
}
No need to add global variables.
Postman have dynamic variable {{$randomInt}} which Adds a random integer between 0 and 1000

Getting results from api

I am trying to do a domain availability search using an API from free domain API.
After i create an account, it shows:
**Make a REST request using this URL:**
http://freedomainapi.com/?key=11223344&domain=freedomainapi.com
And looking in the documentation page, it has only:
Request http://freedomainapi.com?key=YOUR_API_KEY&domain=DOMAIN_NAME
Result:
{
"status": "success",
"domain": "freedomainapi.com",
"available": false
}
I am very new to APIs...
What I need is to show a domain search box, and when the user enters, it should return with result.
It claims to show domain suggestions as well. I hope it will also work.
Using jquery and a jsonp proxy
http://jsfiddle.net/mp8pukbm/1/
$.ajax({
type: 'GET',
url: "https://jsonp.nodejitsu.com/?callback=?",
data: {url: 'http://freedomainapi.com?key=14ejhzc5h9&domain=freedomainapi.com'},
dataType: "jsonp",
success: myfn
});
function myfn(data) {
console.log(data);
}
you have to use the proxy because cross domain json is not permitted
EDIT:
i made an update to show the result in a div (stringified)
http://jsfiddle.net/mp8pukbm/2/
EDIT #2: i created a test key on that site, you have to use your own
EDIT #3: and there's your combo: http://jsfiddle.net/mp8pukbm/4/
Assuming that you will use java script for showing the search box, you can use AJAX feature of java script (or jQuery or Dojo) ... All you need to do is a "GET" request that like you can pasted and you will get the result back on the response object. To try out the API you can use "Postman" application in Chrome. https://chrome.google.com/webstore/detail/postman-rest-client/fdmmgilgnpjigdojojpjoooidkmcomcm?hl=en
In the response object of the AJAX call you will get a JSON object which you can parse and display the result.
Normally when we use REST we need to differentiate one REST call from another.
Assuming this url
http://freedomainapi.com/checkAvailability?key=YOUR_API_KEY&domain=DOMAIN_NAME
In Application layer we need to write an interface
#GET
#Path("/checkAvailability")
#Produces({MediaType.APPLICATION_JSON})
public ReturnObject getDomainAvailability(#QueryParam("key") String key,
#QueryParam("domain") String doaminName );
Once interface is done you need to write your implementation class.
This class will intract with business layer and perform search task and based on
result collected will create ReturnObject.
ReturnObject => will contain status, domain and availability
On screen
$.ajax({
type: "GET",
url: 'root/checkAvailability',
success: function(jsonData)
{
// read json and perform operation
}
,
error: function (error)
{
// handle error
}
});
If you are using JAVA as backend then you can use gson to parse the result, which is a json. After parsing you can read the values from result and display accordingly :)
Any API is a way to extend a given software. (Might be a website or an application)
In both ways there is a certain way to communicate with the software. In your example freedomainapi.com allows you to fetch if given domain is avaiable. There is no such thing as a suggestion tho, atleast i cannot find any suggestions at all.
Given output is a message format know as JSON. It can be easily interpreted by many major Languages such as Java, Javascript and PHP.
Given String might be easily interpreted as a Map consisting of a status (String), a domain (string) and avaiable (boolean)
A domain availability search could not be easier, assuming K is your key, D is your search input (Domain):
Download http://freedomainapi.com/checkAvailability?key=K&domain=D as input
Parse JSON from input as json
return json["status"] == "success" and json["avaiable"]
Depending on your language you might need to use methods to access properties of json, but that does not influence the basic usage of this api.
on user enters, it calls click_button function and I am assuming your result displaying div id is "main_container" you can give domain suggestions by passing related DOMAIN_NAME s as arguments to click_button function
function click_button(DOMAIN_NAME){
$.ajax({
url : 'http://freedomainapi.com?key=YOUR_API_KEY&domain=DOMAIN_NAME',
type: 'GET',
crossDomain: true,
contentType: "application/json; charset=utf-8",
success: function(data) {
data=JSON.parse(data);
if(data['available']){
$('#main_container').html($('#main_container').html()+'<br>'+DOMAIN_NAME+': Available');
else{
$('#main_container').html($('#main_container').html($('#main_container').html()+'<br>'+DOMAIN_NAME+': Not Available');
}//success
});//ajax
}
hope it helpful !

how to upload a file from node.js

I found many posts when I queried for this problem, but they all refer to how to upload a file from your browser to a node.js server. I want to upload a file from node.js code to another server. I tried to write it based on my limited knowledge of node.js, but it doesn't work.
function (data) {
var reqdata = 'file='+data;
var request = http.request({
host : HOST_NAME,
port : HOST_PORT,
path : PATH,
method : 'POST',
headers : {
'Content-Type' : 'multipart/form-data',
'Content-Length' : reqdata.length
}
}, function (response) {
var data = '';
response.on('data', function(chunk) {
data += chunk.toString();
});
response.on('end', function() {
console.log(data);
});
});
request.write(reqdata+'\r\n\r\n');
request.end();
})
The above function is called by other code that generates data.
I tried to upload same data file using curl -F "file=#<filepath>" and the upload is successful. But my code fails. The server returns an application specific error which hints that the uploaded file was invalid/corrupt.
I collected tcpdump data and analysed it in wireshark. The packet sent from my node.js code lacks the boundary required for the multipart data. I see this message in wireshark packet
The multipart dissector could not find the required boundary parameter.
Any idea how to accomplish this in node.js code?
jhcc's answer is almost there.
Having to come up with support for this in our tests, I tweaked it slightly.
Here's the modified version that works for us:
var boundaryKey = Math.random().toString(16); // random string
request.setHeader('Content-Type', 'multipart/form-data; boundary="'+boundaryKey+'"');
// the header for the one and only part (need to use CRLF here)
request.write(
'--' + boundaryKey + '\r\n'
// use your file's mime type here, if known
+ 'Content-Type: application/octet-stream\r\n'
// "name" is the name of the form field
// "filename" is the name of the original file
+ 'Content-Disposition: form-data; name="my_file"; filename="my_file.bin"\r\n'
+ 'Content-Transfer-Encoding: binary\r\n\r\n'
);
fs.createReadStream('./my_file.bin', { bufferSize: 4 * 1024 })
.on('end', function() {
// mark the end of the one and only part
request.end('\r\n--' + boundaryKey + '--');
})
// set "end" to false in the options so .end() isn't called on the request
.pipe(request, { end: false }) // maybe write directly to the socket here?
Changes are:
ReadableStream.pipe returns the piped-to stream, so end never gets called on that. Instead, wait for end on the file read stream.
request.end puts the boundary on a new line.
Multipart is pretty complex, if you want to make it look like how a client usually handles "multipart/form-data", you have to do a few things. You first have to select a boundary key, this is usually a random string to mark the beginning and end of the parts, (in this case it would be only one part since you want to send a single file). Each part (or the one part) will need a header (initialized by the boundary key), setting the content-type, the name of the form field and the transfer encoding. Once the part(s) are completed, you need to mark the end of each part with the boundary key.
I've never worked with multipart, but I think this is how it could be done. Someone please correct me if I'm wrong:
var boundaryKey = Math.random().toString(16); // random string
request.setHeader('Content-Type', 'multipart/form-data; boundary="'+boundaryKey+'"');
// the header for the one and only part (need to use CRLF here)
request.write(
'--' + boundaryKey + '\r\n'
// use your file's mime type here, if known
+ 'Content-Type: application/octet-stream\r\n'
// "name" is the name of the form field
// "filename" is the name of the original file
+ 'Content-Disposition: form-data; name="my_file"; filename="my_file.bin"\r\n'
+ 'Content-Transfer-Encoding: binary\r\n\r\n'
);
fs.createReadStream('./my_file.bin', { bufferSize: 4 * 1024 })
// set "end" to false in the options so .end() isnt called on the request
.pipe(request, { end: false }) // maybe write directly to the socket here?
.on('end', function() {
// mark the end of the one and only part
request.end('--' + boundaryKey + '--');
});
Again, I've never done this before, but I think that is how it could be accomplished. Maybe someone more knowledgable could provide some more insight.
If you wanted to send it as base64 or an encoding other than raw binary, you would have to do all the piping yourself. It will end up being more complicated, because you're going to have to be pausing the read stream and waiting for drain events on the request to make sure you don't use up all your memory (if it's not a big file you generally wouldn't have to worry about this though). EDIT: Actually, nevermind that, you could just set the encoding in the read stream options.
I'll be surprised if there isn't a Node module that does this already. Maybe someone more informed on the subject can help with the low-level details, but I think there should be a module around somewhere that does this.
As the error message states you are missing the boundary parameter. You need to add a random string to separate each file from the rest of the files/form-data.
Here is how a request could look like:
The content type:
Content-Type:multipart/form-data; boundary=----randomstring1337
The body:
------randomstring1337
Content-Disposition: form-data; name="file"; filename="thefile.txt"
Content-Type: application/octet-stream
[data goes here]
------randomstring1337--
Note that the -- in the beginning and end of of the random string in the body is significant. Those are part of the protocol.
More info here http://www.w3.org/Protocols/rfc1341/7_2_Multipart.html
The fastest way I was able to do this, that worked, was using the request package. The code was well documented and it just worked.
(For my testing I wanted a JSON result and non-strict SSL - there are many other options...)
var url = "http://"; //you get the idea
var filePath = "/Users/me/Documents/file.csv"; //absolute path created elsewhere
var r = request.post( {
url: url,
json: true,
strictSSL: false
}, function( err, res, data ) {
//console.log( "Finished uploading a file" );
expect( err ).to.not.be.ok();
expect( data ).to.be.ok();
//callback(); //mine was an async test
} );
var form = r.form();
form.append( 'csv', fs.createReadStream( filePath ) );