The Null value used for query parameters which are null option does not work for a parameter of type string.
I created a GET method with this signature, so I have a string, a DateTime? and a DateTime:
public async Task<ActionResult<bool>> HasOauthMapping(string accessToken, DateTime nonNullableDate, DateTime? nullableDate)
The generated typescript (Angular) code is as follows (with "foo" used for the 'substitute' null value):
if (accessToken !== undefined)
url_ += "accessToken=" + encodeURIComponent("" + accessToken) + "&";
if (nonNullableDate === null)
throw new Error("The parameter 'nonNullableDate' cannot be null.");
else if (nonNullableDate !== undefined)
url_ += "nonNullableDate=" + encodeURIComponent(nonNullableDate ? "" + xnonNullableDate.toJSON() : "foo") + "&";
if (nullableDate !== undefined)
url_ += "nullableDate=" + encodeURIComponent(nullableDate ? "" + nullableDate.toJSON() : "foo") + "&";
url_ = url_.replace(/[?&]$/, "");
As you can see the value "foo" is correctly substituted for both DateTime parameters but for a string parameter a null value gets converted to "" + null or the actual string "null".
I can pass undefined but I'd much prefer for the same logic to apply for all data types.
This is similar to this issue https://github.com/RSuter/NSwag/issues/1168
Have you tried to add [NotNull] (from NJsonSchema) to the string param?
Or [Required]?
If I apply [NotNull to the parameters (reminder that this is a GET
request with method parameters and not a 'property bag') then I get the
following generated in typescript:
if (providerName === null)
throw new Error("The parameter 'providerName' cannot be
null.");
So this is fine for the case where something really is always required,
but sometimes I have two parameters such as userId and accessToken and
only one needs to be provided.
If someone supplies a null instead of undefined then my server starts
looking for someone with a username "null" which will cause all kinds of
confusion!
Wouldn't it always be best to do one of two things for a string:
Either encodeURIComponent(providerName || "")
or encodeURIComponent( providerName ? "" + providerName :
"DEFAULT_VALUE")
The problem obviously is that javascript evaluates "" + null to be
"null"
Personally I don't see myself ever using the 'default value' option, but I
think for sure it should work the same for all data types with "" as the
default.
Thanks
On Fri, Dec 14, 2018 at 2:37 PM Rico Suter notifications@github.com wrote:
Have you tried to add [NotNull] (from NJsonSchema) to the string param?
—
You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub
https://github.com/RSuter/NSwag/issues/1830#issuecomment-447499807, or mute
the thread
https://github.com/notifications/unsubscribe-auth/ADfKVtxGrAOA47TdQwpAKaR13zw_eqt9ks5u5Cg7gaJpZM4ZUQLr
.
Ah yes, there is no way to send a null (not "null") to the server via query parameter, right? So at the moment you'd can only send undefined/nothing, "null" or "mystring"... So what would you expect as when null is passed in param1? Current: param1=null¶m2=abc - better: param1=¶m2=abc?
Maybe a string query parameter can never be nullable, only required or optional?
The default behavior for webAPI is actually to convert an empty string to a
null.
So ?favoriteColor=&favoriteAnimal=dog
Gives a null in the controller.
This behavior can be changed but that’s the default behavior:
So yes I definitely think that the query string produced should look like
what I have above when null is passed in (unless marked as required in
which case you already handle this by throwing an error).
.NET programmers obviously don’t have ‘undefined’ in C# and would tend to
use ‘null’. So when null gets coerced into a string it gets confusing.
On Sat, Dec 15, 2018 at 9:10 AM Rico Suter notifications@github.com wrote:
Maybe a string query parameter can never be nullable, only required or
optional?—
You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub
https://github.com/RSuter/NSwag/issues/1830#issuecomment-447583062, or mute
the thread
https://github.com/notifications/unsubscribe-auth/ADfKVpLvr2gMa9k9_yno4PBDAKfRu5chks5u5SzmgaJpZM4ZUQLr
.
I think we should send “” instead of “null” when passing a null parameter, right? “null” does not make sense in any case...
@RSuter Yes I think that's definitely the best approach.
Personally I doubt I will ever use the 'default null value' you have in nswag studio - but it should probably send that value if defined. But if the default for that value is "" then that will solve this issue anyway.
I would find it very useful if you could customise the "null string" that the Null value used for query parameters which are null promises to do, rather than have it hard-coded to "". In many situations the empty string is a perfectly valid input which is not semantically the same as null, and you need to be able to distinguish between the two. Or you may simply be attempting to connect with a service beyond your control which uses a different convention for representing nulls than this.
Common options include:
/endpoint?foo=%00&bar=1);/endpoint?foo&bar=1 - no equals sign)"" as you say (/endpoint?foo=&bar=1);/endpoint?foo=#NULL#&bar=1 if # is an illegal character, say)APIs vary so support for any of these cases, not just the "" case, would be tremendous.
Or further actually, even better would be an option to wrap optional parameters in a type allowing for disambiguation not just between nulls and empty strings, but also between no argument being provided at all. (I'm going to discuss a C# client as I'm not familiar with TS, but I assume a similar idea would be applicable there.)
At the moment I believe if you choose to generate optional parameters (which is nice as it gives the same C# experience calling a method as the 'direct from URL' experience which the API was probably primarily intended for), a string (for example) will be generated as string myStringArg = null. Providing null explicitly is therefore the same as not providing the argument at all, and that's how the request will be formed to the API.
In many cases these aren't interpreted the same way on the server, though. To alleviate this, we could have a new type:
public readonly struct Optional<T>
{
public bool IsSupplied { get; }
public T Value { get; }
private Optional(bool isSupplied, T value) => (IsSupplied, Value) = (isSupplied, value);
public static implicit operator Optional<T>(T value) => new Optional<T>(true, value);
}
And then instead generate argument method signatures like Optional<string> myStringArg = default when the argument is non-required. Then if you don't supply the argument, the argument can not be added to the URL, and if you do and supply null, a "null value" (whatever that is, given the previous comment) can be given to the URL parameter, and if you supply "", an empty string can be supplied. Enabling this feature could be a switch disabled by default for compatibility.
Most helpful comment
I would find it very useful if you could customise the "null string" that the
Null value used for query parameters which are nullpromises to do, rather than have it hard-coded to"". In many situations the empty string is a perfectly valid input which is not semantically the same asnull, and you need to be able to distinguish between the two. Or you may simply be attempting to connect with a service beyond your control which uses a different convention for representing nulls than this.Common options include:
/endpoint?foo=%00&bar=1);/endpoint?foo&bar=1- no equals sign)""as you say (/endpoint?foo=&bar=1);/endpoint?foo=#NULL#&bar=1if#is an illegal character, say)APIs vary so support for any of these cases, not just the
""case, would be tremendous.