deserialization issue with char '\' - vb.net

Does json.net have an in built method that would escape special characters? My json strings I recv from vendors have \, double " .
If not what is the best way to escape the special charecters before invoking JsonConvert.DeserializeObject(myjsonString)?
My sample json string
{
"EmailAddresses": [
{
"EmailAddress": "N\A"
}
]
}
Pasting this in json lint results in
Parse error on line 4:
... "EmailAddress": "N\A",
-----------------------^
Expecting 'STRING', 'NUMBER', 'NULL', 'TRUE', 'FALSE', '{', '['
VB.NET code
instanceofmytype = JsonConvert.DeserializeObject(Of myType)(myJsonString)
Exception: Newtonsoft.Json.JsonReaderException: Bad JSON escape sequence:

The JSON is not valid: a \ must be followed by one of the following: "\/bfnrtu. Since it's followed by A, Json.NET chokes (as it ought to). The source of your JSON should be fixed. If this is not an option, you can make a guess to fix it yourself, e.g.
myStr = Regex.Replace(myStr, "\\(?=[^""\\/bfnrtu])", "\\")

You shouldn't have to worry about it. JSON.NET handles a lot of nice things for you. It should just work.
Have you tried it?

Related

Karate Api : check if a phrase is available response object array

I've a response
{ errors: [
{
code: 123,
reason: "this is the cause for a random problem where the last part of this string is dynamically generated"
} ,
{
code: 234,
reason: "Some other error for another random reason"
}
...
...
}
Now when I validate this response
I use following
...
...
And match response.errors[*].reason contains "this is the cause"
This validation fails, because there is an equality check for complete String for every reason ,
I all I want is, to validate that inside the errors array, if there is any error object, which has a reason string type property, starting with this is the cause phrase.
I tried few wild cards but didn't work either, how to do it ?
For complex things like this, just switch to JS.
* def found = response.errors.find(x => x.reason.startsWith('this is the cause'))
* match found == { code: 123, reason: '#string' }
# you can also do
* if (found) karate.log('found')
Any questions :)

Karate: Unable to move schema definition out of feature file

I'm able to successfully run the Feature/scenario, When I define the schema inside my feature file .
Here is a simplified example of the schema.
Background:
...
...
* def accountSchema = { id: '#number? _ >= 0', prop1: '#number? _ >= 0', prop2: '#string', prop3: '#string', optionaProp: '##string' }
* def userAccountsSchema = ({ entitledAccounts: '#[] accountSchema', prop5: '#number' , prop6: '##string'})
And here is how I'm validating
Scenario:
...
...
When method GET
Then status 200
* print userAccountsSchema
And match response == userAccountsSchema
But the schema I posted here is simplified to ask this question, the real schema is far more complex.
So for clarity purpose, I decided to put schema in a separate js file response-schemas.js under the same folder as the feature file.
Here is the simplified content of response-schemas.js file.
function schema () {
let accountSchema = {
id: '#number? _ >= 0',
prop1: '#number? _ >= 0',
prop2: '#string',
prop3: '#string',
optionaProp: '##string',
}'
return {
accounts: `#[] ${accountSchema}` ,
prop5: '#string',
prop6: '#string',
};
}
now if I replace the 2 lines I mentioned at the beginning of the question under Background:, with below line
* def userAccountsSchema = call read('response-schemas.js')
I get this error
And match response == schemas
SyntaxError: Unnamed:1:8 Expected comma but found ident
[object Object]
^
I believe, I understand the problem, is this line
accounts: `#[] ${accountSchema}` ,
but unable to figure out the solution. If I tried to change the accountSchema variable in response-schemas.js to use multiline string then I get error in read step in Background
the whole idea to have a dedicated js file for schema is to keep it readable (by using multiple lines, preferably objects not a long string)
The main problem is this part:
accounts: `#[] ${accountSchema}`
Where you are trying to stuff a JSON into the Karate "fuzzy" expression. This is just not supported. Note that the Karate way of defining things like #(foo) and #[] bar has nothing to do with JavaScript, so I recommend not mixing these.
I know there is a desire to achieve the match in just one-line and somehow get one monstrous schema to do everything and I very strongly discourage this. Split your assertions into multiple lines. Split your response into smaller chunks of JSON if needed. There is nothing wrong with that. This also makes the life much easier of people who come along later who have to maintain your test.
For ideas see this answer: https://stackoverflow.com/a/61252709/143475
Other answers: https://stackoverflow.com/search?q=%5Bkarate%5D+array+schema
Tip: you can keep your schema "chunks" as JSON files if needed.

How to commit to an alternation branch in a Raku grammar token?

Suppose I have a grammar with the following tokens
token paragraph {
(
|| <header>
|| <regular>
)
\n
}
token header { ^^ '---' '+'**1..5 ' ' \N+ }
token regular { \N+ }
The problem is that a line starting with ---++Foo will be parsed as a regular paragraph because there is no space before "Foo". I'd like to fail the parse in this case, i.e. somehow "commit" to this branch of the alternation, e.g. after seeing --- I want to either parse the header successfully or fail the match completely.
How can I do this? The only way I see is to use a negative lookahead assertion before <regular> to check that it does not start with ---, but this looks rather ugly and impractical, considering that my actual grammar has many more than just these 2 branches. Is there some better way? Thanks in advance!
If I understood your question correctly, you could do something like this:
token header {
^^ '---' [
|| '+'**1..5 ' ' \N+
|| { die "match failed near position $/.pos()" }
]
}

Trouble parsing URL encoded URI using read(data, "application/x-www-form-urlencoded") function in Dataweave 2.0

I have this url from which I am trying to retrieve the queryParams.
%dw 2.0
output application/json
import * from dw::core::URL
---
{
queryParams : read(parseURI("https://google.com?token=abc%2FL℅2Bxyz%2F").query default "", "application/x-www-form-urlencoded")
}
Output
{
"queryParams": {
"token": "abc/L xyz/"
}
}
Based on url encoding, / is %2F and + is %2B. But in the output I got a space in place of +.
I understand that parseURI is basically decoding the URI to just "token=abc/L+xyz/", but why does applying a read(data, "application/x-www-form-urlencoded") on top of it change the value to abc/L xyz/?
I am trying understand this behavior as I am trying to retrieve the original URI. For that I did the below
encodeURIComponent(read(parseURI("https://google.com?token=abc%2FL℅2Bxyz%2F").query default "", "application/x-www-form-urlencoded").token)
The output for the above line of code is "abc%2F%20xyz%2F". So %2B is getting converted to %20.
Firstly there are some issues with your script as shown. It doesn't to work as is because the package import is case sensitive. Also it uses the character ℅ instead of the percentage character % for 2B. After fixing those issues what you described can be reproduced.
I changed the script to show both the output of parseURI() and read(). You can see that parseURI() returns a + which is expected. Then using read() with media type "application/x-www-form-urlencoded" you are telling read that the content is to be parsed in urlencoded form format. That implies converting a + into a space character to obtain the actual URL. See this answer about URL encoding for more details.
Using encodeURI() to reencode the output will return %20 instead of +, which seems to be more canonical.
If you absolutely need the original string you may want to use string operations or regular expressions to decompose the query string into the token value.
Example:
Script
%dw 2.0
output application/json
import * from dw::core::URL
var parsed=parseURI("https://google.com?token=abc%2FL%2Bxyz%2F").query
---
{
parsed : parsed,
read: read(parsed default "", "application/x-www-form-urlencoded").token,
encoded: encodeURI(read(parsed default "", "application/x-www-form-urlencoded").token)
}
Output
{
"parsed": "token=abc/L+xyz/",
"read": "abc/L xyz/",
"encoded": "abc/L%20xyz/"
}
Example of obtaining the token using string operations (splitBy()) and some mapping.
%dw 2.0
output application/json
import * from dw::core::URL
var parsed=parseURI("https://google.com?token=abc%2FL%2Bxyz%2F&other=1234").query
---
{
queryParam : parsed splitBy "&"
map ( (($ splitBy "=")[0]): ($ splitBy "=")[1] )
reduce ((item, acc={}) -> acc ++ item)
}
Output:
{
"queryParam": {
"token": "abc/L+xyz/",
"other": "1234"
}
}

Convert CachedOutputStream to a string

Convert CachedOutputStream to a string.
After upgrading camel from 2.12 to 2.23 I have a problem on my route, same code same route.
The response after calling a endpoint is of type org.apache.camel.converter.stream.CachedOutputStream
I tried to convert the CachedOutputStream to a String.
String body = exchange.getIn().getBody(String.class);
logger.info("FJA the string after caling endpoint: " + body);
I dk.bankconnect.hub.Util efter FJA efter streng er:
-0��phjA����/h`�FhI[����G<�����,�Z���f���=��Rϝ��s#���O��~#�G�t
How to convert the CachedOutputStream to a string?
I tried many different things to avoid the response to come as a stream. However, I do not succeeded.
Here is a little snippet of my route:
from("direct:sdc:webservice")
.setProperty("webservice", constant(Boolean.TRUE))
.setProperty("duration", simple("Forwarding request to ${property.datacentral} datacentral"))
.choice().when().simple("${property.Tracked} == true").bean(Util.class, "dura-tion").end()
.bean(Util.class, "tracker")
.bean(Util.class, "foer")
.to(Util.getProperty("sdc.url"))
.bean(Util.class, "efter")
.convertBodyTo(Document.class)
.setProperty("duration", simple("Receiving response from ${proper-ty.datacentral} datacentral"))
.choice().when().simple("${property.Tracked} == true").bean(Util.class, "dura-tion").end()
.bean(Util.class, "tracker")
.setProperty(SoapError.FAULT, xpath("/soapenv:Envelope/soapenv:Body/soapenv:Fault/faultstring/text()", String.class).namespace("soapenv", Namespace.SOAP))
.end();
My convertBodyTo fails, because its suddenly a stream.
Ok, very short
The response after calling a endpoint is of type org.apache.camel.converter.stream.CachedOutputStream
I tried to convert the CachedOutputStream to a String.
String body = exchange.getIn().getBody(String.class);
This is not a String that is readable, but many special characters.
Frank :-)