URI-encoding a string - krl

I need to send a GET request. One of the parameters has URL query characters in it (e.g., ?, &, and =). How do I URI-encode that in KRL before sending the request?
Here's the pseudocoded idea:
params = "key=value&key=value";
encoded_params = params.urlencode();
request = datasource:service("?data=#{encoded_params}");

You can either pass a string or a struct when you call a datasource. When you use a hash, the hash values are URL encoded automagically by the platform.
Your code above would be written like so:
rparams = {
"key1": "value1",
"key2": "value2"
};
request = datasource:service(rparams);
TaDa! Magic.
Note that I used string literals in the hash declaration, but those can be any expressions, and the values will be passed as the arguments in the datasource request.

See also http://docs.kynetx.com/docs/URI
escaped = uri:escape("a b c d"); // "a%20b%20c%20d"
original = uri:unescape(escaped); // "a b c d"

Related

Accidentally URL Encoding URI Twice, Invalid Signature Response

I'll try to explain this best I can. I'm trying to perform a simple GET against the NetSuite "employees" API (using PowerShell). As you can see in the $query below, this variable needs to be URL encoded (spaces in the query) which I am doing on line 20 of the below snippet. I'm then taking that encoded URL along with a couple other variables and building the $base_string. I use the $base_string to create the Base64 OAuth signature and, on line 36, URL encode the signature. My response from NetSuite is always Invalid Signature.
When I perform any sort of "standard" query (like the one immediately below, without spaces... meaning no changes to the URL after encoding) I do not get an Invalid Signature response. This leads me to believe the problem is entirely related to the more unique query I am attempting and, possibly, the fact that it is being "double-encoded."
I'd appreciate any feedback as I would really benefit from being able to perform a query against the "custentity" variable in the below snippet.
$query = "/services/rest/record/v1/employee/$($netsuite_id)" # This query will find a user via their NetSuite ID.
$url = "https://$($realm.ToLower().Replace("_","-")).suitetalk.api.netsuite.com"
$query = "/services/rest/record/v1/employee?q=custentity_coupa_emp_id IS $($employee_id)" # This query will find a user via a custom entity --- their Coupa ID.
$oauth_nonce = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes([System.DateTime]::Now.Ticks.ToString()))
$oauth_timestamp = [int64](([datetime]::UtcNow)-(Get-Date "1970-01-01")).TotalSeconds
# BUILD THE BASE STRING VARIABLE
$oAuthParamsForSigning = #{}
$oAuthParamsForSigning.Add("oauth_consumer_key",$oauth_consumer_key)
$oAuthParamsForSigning.Add("oauth_token",$oauth_token)
$oAuthParamsForSigning.Add("oauth_signature_method",$oauth_signature_method)
$oAuthParamsForSigning.Add("oauth_nonce",$oauth_nonce)
$oAuthParamsForSigning.Add("oauth_timestamp",$oauth_timestamp)
$oAuthParamsForSigning.Add("oauth_version",$oauth_version)
$oAuthParamsString = ($oAuthParamsForSigning.Keys | Sort-Object | % {
"$_=$($oAuthParamsForSigning[$_])"
}) -join "&"
$encodedOAuthParamsString = [uri]::EscapeDataString($oAuthParamsString)
# BUILD THE ENCODED FULL URL VARIABLE
$encodedUrl = [uri]::EscapeDataString($url+$query)
# BUILD THE OAUTH SIGNATURE VARIABLE: KEY (CONSUMER SECRET + TOKEN SECRET) + BASE STRING
$base_string = $HTTP_method + "&" + $encodedUrl + "&" + $encodedOAuthParamsString
$key = $oauth_consumer_secret + "&" + $oauth_token_secret
$hmacsha256 = New-Object System.Security.Cryptography.HMACSHA256
$hmacsha256.Key = [System.Text.Encoding]::ASCII.GetBytes($key)
$oauth_signature = [System.Convert]::ToBase64String($hmacsha256.ComputeHash([System.Text.Encoding]::ASCII.GetBytes($base_string)))
# BUILD THE HEADERS VARIABLE
$authHeaderString = ($oAuthParamsForSigning.Keys | Sort-Object | % {
"$_=`"$([uri]::EscapeDataString($oAuthParamsForSigning[$_]))`""
}) -join ","
$authHeaderString += ",realm=`"$([uri]::EscapeDataString($realm))`""
$authHeaderString += ",oauth_signature=`"$([uri]::EscapeDataString($oauth_signature))`""
$authHeaders = #{
"Content-Type"="application/json"
;"Prefer"="transient"
;"Authorization"="OAuth $authHeaderString"
;"Accept"="*/*"
;"Cache-Control"="no-cache"
;"Host"="3489459-sb1.suitetalk.api.netsuite.com"
;"Accept-Encoding"="gzip, deflate, br"
;"Cookie"="NS_ROUTING_VERSION=LAGGING"
}
I have no background with PowerShell but I've had this issue previously with Python and it's tricky without using libraries. I found out that:
Your Base URL cannot contain query params. Meaning your base url should be:
"https://$($realm.ToLower().Replace("_","-")).suitetalk.api.netsuite.com/services/rest/record/v1/employee"
Since you're only doing GET request, just throw your query into a payload (JSON formatted). At least with my SuiteQL this is how I did it. Moving the query to payload worked for me.
For POST Request, the parameters will need to be included in the Base String Creation, sorted alphabetically or by value if keys are the same name.
My query for example for SuiteQL was query = json.dumps({ q: SELECT FROM WHERE })

How to insert a placeholder in a json key:value ? Flutter

I'm porting my Swift app to Flutter and for localising it I'm following this https://github.com/billylev/flutter_localizations but I can't see how to insert placeholder to insert a value in the translated values.
Basically the guide uses
String text(String key) {
return _localisedValues[key] ?? "$key not found";
}
to get the corresponding key:value pair from a .json file as
{
"Shop": "Negozio",
}
I just pass it in the Textwidget as :
Text(AppLocalizations.instance.text('Shop')).
How to modify text to insert one or more placeholders and how would be the .json be constructed?
Say for the value "User": "User" I'd like to insert a value after the transaction I can simply use a string sum and add the value as `Text(
AppLocalizations.instance.text('User') + ' ${widget.user.name}', but if I need to insert a value in the middle of the translated sentence, eg a message, I don't see how to accomplish it.
I need it to make localised versions of incoming push notification, and they have args.
In Swift I have it like this:
"ORDER_RECEIVED_PUSH_TITLE" = "Order number: %#";
"ORDER_RECEIVED_PUSH_SUBTITLE" = "Shop: %#";
"ORDER_RECEIVED_PUSH_BODY" = "Thank you %#! We received your order and we'll let you know when we start preparing it and when it's ready. Bye";
Any suggestions on how to accomplish that in Flutter?
Many thanks
I was suggested this package https://pub.dev/packages/sprintf#-installing-tab- and it works just as I needed. Sprintf just lets you specify one or more placeholders in a String and pass an array of args.
https://developermemos.com/posts/using-sprintf-flutter-dart. for more info, even this is pretty much it. So for example
"ORDER_RECEIVED_PUSH_TITLE" = "Order number: %#";
in the .json file would be :
{
"ORDER_RECEIVED_PUSH_TITLE": "Oder number: %s"
}
and using it would be
String orderNumber = 'some uuid';
Text(Sprintf(AppLocalitazions.instance.text('ORDER_RECEIVED_PUSH_TITLE'),[orderNumber]);
Hope this helps others.

Can't unescape escaped string with ABAP

I want to escape this string in SAPUI5 like this.
var escapedLongText = escape(unescapedLongText);
String (UTF-8 quote, space, Unicode quote)
" “
Escaped string
%22%20%u201C
I want to unescape it with this method, but it returns empty. Any ideas?
DATA: LV_STRING TYPE STRING.
LV_STRING = '%22%20%u201C'.
CALL METHOD CL_HTTP_UTILITY=>UNESCAPE_URL
EXPORTING
ESCAPED = LV_STRING
RECEIVING
UNESCAPED = LV_STRING.
I changed the code in SAPUI5 to the following:
var escapedLongText = encodeURI(unescapedLongText);
This results in: (like andreas mentioned)
%22%20%e2%80%9c
If I want to decode it later in SAPUI5, it can be done like this:
var unescapedLongText = unescape(decodeURI(escapedLongText));
The unescape needs to be done, because commas (for example) don't seem to be decoded automatically.

how to verify in assertj that elements are one of

I can't find how to do check with assertj the following (which is very common):
Suppose I have:
result1 = {"AAA", "BBB"}
result2 = {"DDD"}
I want to check the values in result is one of these:
String[] valid = String[]{"AAA", "BBB", "CCC"};
using assertj, whould be something as:
assertThat(result1).xxxx(valid);
assertThat(result2).xxxx(valid);
So that result1 would pass check, but result2 not.
contains() does not work (it checks that result contains all valid elements)
I don't want have to create a custom condition for this kind of checking
Any idea?
You can wtite it the other way around:
assertThat(valid).contains(result1);
assertThat(valid).contains(result2);
If you insist on having the result on the left and valid on the right side, you can use:
assertThat(result1).isSubsetOf(Arrays.asList(valid));
assertThat(result2).isSubsetOf(Arrays.asList(valid));
Or, why not to define the valid as a set, rather than an array?
Set<String> valid = Sets.newHashSet("AAA", "BBB", "CCC"); //Sets comes from google guava
assertThat(result1).isSubsetOf(valid);
assertThat(result2).isSubsetOf(valid);

Parse Json array response in scala\Play

There is a web service returning array of something
{"apps": [{"name": "one"}, {"name": "two"}]}
In my code I want to iterate every name
val request = WS.url(s"http://localhost:9000/getData")
val json = request.get.map { response =>
(response.json \ "apps" \\ "name")
}
json.foreach(println)
However all my attempts return single record
// Expect
one
two
// Actual
ListBuffer("one", "two")
First of all, the neat solution here would be:
val request = WS.url(s"http://localhost:9000/getData")
request.get.map { response =>
val names = (response.json \ "apps" \\ "name")
names.foreach(println)
}
Secondly, if you don't want to get confused about the types, you should change your naming standards. For a Future object, you may start with the prefix future, for an Option, it could start with maybe, etc. If you do so, the problem in your example will be more obvious:
val request = WS.url(s"http://localhost:9000/getData")
val futureJson = request.get.map { response =>
(response.json \ "apps" \\ "name")
}
futureJson.foreach(println) // you call foreach for a Future, not for a List
Thirdly, why would Future trait have a method called foreach? I think that's confusing for beginners and even mid-level developers. We know from other languages that, foreach means iterate over a list of objects. In Scala, it is considered part of "Monadic operations" which is still a gray area for me :), but the comment for Future.foreach in Scala source is this:
/** Asynchronously processes the value in the future once the value becomes available.
*
* Will not be called if the future fails.
*/
def foreach[U]
Your value of json is actually a Future[Seq[JsValue]], so when you foreach over the future you get the entire list back. You would need an additional foreach to iterate over the list of values.