I have to pass a 2d integer array to get REST call.
Example:[[1,2,3], [5,10,11]]
I can pass it by entering data separately into the parameter like
Example: http://localhost:1136/demo?x=3,4,5&x=10,11,12
But I want it to be like
?x=[[1,2,3], [5,10,11]]
Any suggestion
You can define a #RequestParam(value= "x") String[][] like this:
#GetMapping(value = "/demo")
public void demo(#RequestParam(value= "x") String[][] array2d) {
// You will get: array2d = [[3,4,5],[10,11,12]]
}
Note: You may get the valid characters are defined in RFC 7230 and RFC 3986 error.
You can add to application.properties file something like this:
tomcat.relaxed-query-chars="|,{,},[,]"
Related
I am trying to get the first row and the last row of a query result. I see from Ci4's docs, there are two methods to help, namley, getFirstRow([$type = 'object']) and getLastRow([$type = 'object']) but I am having difficulty using them. Here is my method so far:
function getLoginFailCount($login_fail_ip, $max_login_attempts = 3, $within_seconds = 320){
$builder = $this->builder('login_fail');
$builder->where('login_fail_ip', $login_fail_ip);
$builder->orderBy('login_fail_created_at','DESC');
$query = $builder->get(3);
print_r($query->getFirstRow($query));
}
I get an error at getFirstRow as follows;
Argument 1 passed to CodeIgniter\Database\BaseResult::getFirstRow() must be
of the type string, object given
How can I get getFirstRow() to work? Doesn't this doc definition say I need to pass it an object? Why does the error say it my be of type string
Well in the documentation for getFirstRow() it states that you can use
$row = $query->getFirstRow() // which will give you an object
OR
$row = $query->getFirstRow(‘array’) // which will give you an Array
So your error message, which states...
Argument 1 passed to CodeIgniter\Database\BaseResult::getFirstRow()
must be of the type string, object given
Would make you look and say to yourself, I had better go and read the documentation. So you can either pass in nothing, or a String 'array'.
So now can you see why
$query->getFirstRow($query))
does not make any sense! Why would you pass in the $query object as parameter.
You may have misread the documentation. I see you stated getFirstRow([$type = 'object'])
You might have got a little confused by that...
[$type = 'object'] means that the $type is defaulted to be the string 'object' so the returned type is an object by default with No Parameter being passed in.
If you want it to return an array, then you would specify the string 'array'. So then the $type parameter would be set to the string 'array' and return an array instead of an object.
Does that help!
How do I test for the correct test results when my returned array is unordered? My test fails because the order they are in the array is different on each test run. How can I fix this or account for an unordered array?
mockMvc.perform(delete("/deleteSomeObject" + "/objIdLong" + "/objFKeyString"))
.
.
.andExpect(jsonPath("$[0].id.objIdLong", is(533252)))
.andExpect(jsonPath("$[0].id.objFKeyString", is("SomeString")))
.andExpect(jsonPath("$[1].id.objIdLong", is(642654252)))
.andExpect(jsonPath("$[1].id.objFKeyString", is("ThisString")))
.andExpect(jsonPath("$[2].id.objIdLong", is(4624352)))
.andExpect(jsonPath("$[2].id.objFKeyString", is("SomeOtherString")));
You could use the 'any element' instruction and to prevent false positives where one element has the expected objIdLong and another element has the expected objFKeyString you could combine the accessors.
Something like this:
.andExpect(jsonPath('$.id[?(#.objIdLong == 533252 && #.objFKeyString == \'SomeString\')]').exists())
.andExpect(jsonPath('$.id[?(#.objIdLong == 642654252 && #.objFKeyString == \'ThisString\')]').exists())
.andExpect(jsonPath('$.id[?(#.objIdLong == 4624352 && #.objFKeyString == \'SomeOtherString\')]').exists())
These assertions will be deemed true as long as the returned JSON contains:
An id sub document with objIdLong=533252 and objFKeyString="SomeString"
An id sub document with objIdLong=642654252 and objFKeyString="ThisString"
An id sub document with objIdLong=4624352 and objFKeyString="SomeOtherString"
At the time of writing there was an easier way of doing it .andExpect(content().json(expected_response))
.json(expected_response) validation has an option to do a strict or a lenient checking. This is helpful for arrays where you do not care about response ordering which can change. If you want to turn strict checking it on you can turn it on like .json(expected_response,true) . Also you can load your whole response from a file reader and do a direct assert without having to tediously write json path. Here is a complete example.
#Test
#DisplayName("invalid fields")
void invalidfields() throws Exception {
String request = getResourceFileAsString("test-data/http-request/invalid-fields.json");
String response_file_path = "test-data/http-response/error-messages/invalid-fields.json";
String expected_response = getResourceFileAsString(response_file_path);
mockMvc.perform(evaluateRulesOnData(TRACKING_ID.toString(), request))
.andExpect(status().isBadRequest())
.andExpect(content().json(expected_response));
}
helper function to load test files from classpath
public static String getResourceFileAsString(String fileName) throws IOException {
Resource resource = new ClassPathResource(fileName);
File file = resource.getFile();
return new String(Files.readAllBytes(file.toPath()));
}
The expected response has an array with many elements in the list which are matched despite being in random order during each test run.
I'm new to SoapUI. I wanted to know how can we add 2 property value into one Header value.
For instance, I got some response like in XML format:
<Response xmlns="Http://SomeUrl">
<access_token>abc</access_token>
<scope>scope1</scope>
<token_type>Bearer</token_type>
</Response>
I want to send both access_token & token type to a single header value like:
"Authorization":"Bearer abc"
I am not getting how to do this using property transfer step.
Can anyone please help me?
You can use XPath concat function to concatenate the both values in one variable in your property transfer steps, in your case you can use the follow XPath:
concat(//*:token_type," ",//*:access_token)
concat function concatenates two or more strings, //*:token_type gets the Bearer value and //*:access_token gets the abc.
Hope this helps,
Add a script step after the step returning what you describe above.
def tokenType = context.expand('${STEP RETURNING STUFF#Response#//Response/token_type}');
def token = context.expand('${STEP RETURNING STUFF#Response#//Response/access_token}');
//add header to all steps
for (def stepEntry : testRunner.testCase.testSteps) {
if (!(stepEntry.value instanceof com.eviware.soapui.impl.wsdl.teststeps.WsdlTestRequestStep)) {
continue;
}
def headers = stepEntry.value.httpRequest.requestHeaders;
headers.remove("Authorization");
headers.put("Authorization", token_type + " " + token);
stepEntry.value.httpRequest.requestHeaders = headers;
}
Here is another way without using additional property transfer step, but uses script assertion
Add a script assertion for the request test step.
Use below code into that script, modify element XPath are required
def element1Xpath = '//*:token_type'
def element2Xpath = '//*:access_token'
def groovyUtils = new com.eviware.soapui.support.GroovyUtils( context )
def response = groovyUtils.getXmlHolder(messageExchange.responseContentAsXml)
def field1 = response.getNodeValue(element1Xpath)
def field2 = response.getNodeValue(element2Xpath)
if (!field1) { throw new Error ("${element1Xpath} is either empty or null") }
if (!field1) { throw new Error ("${element2Xpath} is either empty or null") }
context.testCase.setPropertyValue('TEMP_PROPERTY', "${field1} ${field2}")
Now the expected value(merged) is available in a property 'TEMP_PROPERTY'. You may rename the property name as you wish in the last line of the code.
You may the new wherever it is needed within the test case.
Given this ApiController:
public string TestString() {
return "The value is: " + 1.23;
}
public double TestDouble() {
return 1.23;
}
With the browser's language set to "fr-FR", the following happens:
/apiController/TestString yields
<string xmlns="http://schemas.microsoft.com/2003/10/Serialization/">The value is: 1,23</string>
/apiController/TestDouble yields
<double xmlns="http://schemas.microsoft.com/2003/10/Serialization/">1.23</double>
I would expect TestDouble() to yield 1,23 in the XML. Can anyone explain why this isn't the case and, more importantly, how to make it so that it does?
It is because the conversion from double to string happens at different stage for each API. For the TestString API, double.ToString() is used to convert the number to a string using CurrentCulture of the current thread and it happens when the TestString method is called. Meanwhile, the double number which is returned by TestDouble is serialized to string during the serialization step which uses GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.Culture.
In my opinion, both should use InvariantCulture. On the consumer side, the values will be parsed and be formatted with the correct culture.
Update: this is only used for JsonFormatter. XmlFormatter doesn't have such a setting.
Update 2:
It seems (decimal) numbers need special converter to make it culture-aware:
Handling decimal values in Newtonsoft.Json
Btw, if you want o change data format per action/request, you can try the last piece of code of the following link: http://tostring.it/2012/07/18/customize-json-result-in-web-api/
How do I create an if statement saying something like this?
Basically, how do you use the URI class to determine if there is a value in any segment?
$segment = value_of_any_segment;
if($segment == 1{
do stuff
}
I know this is pretty elementary, but I don't totally understand the URI class...
Your question is a little unclear to me, but I'll try to help. Are you wondering how to determine if a particular segment exists or if it contains a specific value?
As you are probably aware, you can use the URI class to access the specific URI segments. Using yoursite.com/blog/article/123 as an example, blog is the 1st segment, article is the 2nd segment, and 123 is the 3rd segment. You access each using $this->uri->segment(n)
You then can construct if statements like this:
// if segment 2 exists ("articles" in the above example), do stuff
if ($this->uri->segment(2)) {
// do stuff
}
// if segment 3 ("123" in the above example) is equal to some value, do stuff
if ($this->uri->segment(3) == $myValue) {
// do stuff
}
Hope that helps! Let me know if not and I can elaborate or provide additional information.
Edit:
If you need to determine if a particular string appears in any segment of the URI, you can do something like this:
// get the entire URI (using our example above, this is "/blog/article/123")
$myURI = $this->uri->uri_string()
// the string we want to check the URI for
$myString = "article";
// use strpos() to search the entire URI for $myString
// also, notice we're using the "!==" operator here; see note below
if (strpos($myURI, $myString) !== FALSE) {
// "article" exists in the URI
} else {
// "article" does not exist in the URI
}
A note regarding strpos() (from the PHP documentation):
This function may return Boolean
FALSE, but may also return a
non-Boolean value which evaluates to
FALSE, such as 0 or "". Please read
the section on Booleans for more
information. Use the === operator for
testing the return value of this
function.
I hope my edit helps. Let me know if I can elaborate.