0

I use NSwag to generate TypeScript code. The generated nswag code sends null when I use an nullable int in a Web API.

How do I prevent NSwag to generated this code or allow .NET Core 3.1 to accept this as a valid value?

http://localhost:4000/api/SurveyManagement/UpdateRouteSurvey?toSurveyId=null

Generated TypeScript code:

updateRouteSurvey(toSurveyId: number | null): Observable<void> {
        let url_ = this.baseUrl + "/api/SurveyManagement/UpdateRouteSurvey?";
        if (toSurveyId === undefined)
            throw new Error("The parameter 'toSurveyId' must be defined.");
        else
            url_ += "toSurveyId=" + encodeURIComponent("" + toSurveyId) + "&"; 
        url_ = url_.replace(/[?&]$/, "");
...

C# API interface

  [HttpPost(nameof(UpdateRouteSurvey))]
        public async Task UpdateRouteSurvey(int? toSurveyId) =>
            await _manageSurveyService.UpdateRouteSurvey(toSurveyId);

NSwag config

 "openApiToTypeScriptClient": {
      "className": "{controller}Client",
      "moduleName": "",
      "namespace": "",
      "typeScriptVersion": 2.7,
      "template": "Angular",
      "promiseType": "Promise",
      "httpClass": "HttpClient",
      "useSingletonProvider": false,
      "injectionTokenType": "InjectionToken",
      "rxJsVersion": 6.0,
      "dateTimeType": "Date",
      "nullValue": "Null",
      "generateClientClasses": true,
      "generateClientInterfaces": false,
      "generateOptionalParameters": false,
      "exportTypes": true,
      "wrapDtoExceptions": false,
      "exceptionClass": "SwaggerException",
      "clientBaseClass": null,
      "wrapResponses": false,
      "wrapResponseMethods": [],
      "generateResponseClasses": true,
      "responseClass": "SwaggerResponse",
      "protectedMethods": [],
      "configurationClass": null,
      "useTransformOptionsMethod": false,
      "useTransformResultMethod": false,
      "generateDtoTypes": true,
      "operationGenerationMode": "MultipleClientsFromOperationId",
      "markOptionalProperties": false,
      "generateCloneMethod": false,
      "typeStyle": "Interface",
      "classTypes": [],
      "extendedClasses": [],
      "extensionCode": null,
      "generateDefaultValues": false,
      "excludedTypeNames": [],
      "excludedParameterNames": [],
      "handleReferences": false,
      "generateConstructorInterface": true,
      "convertConstructorInterfaceData": false,
      "importRequiredTypes": true,
      "useGetBaseUrlMethod": false,
      "baseUrlTokenName": "API_BASE_URL",
      "queryNullValue": "",
      "inlineNamedDictionaries": false,
      "inlineNamedAny": false,
      "templateDirectory": null,
      "typeNameGeneratorType": null,
      "propertyNameGeneratorType": null,
      "enumNameGeneratorType": null,
      "serviceHost": null,
      "serviceSchemes": null,

    }
Thom Kiesewetter
  • 6,703
  • 3
  • 28
  • 41

1 Answers1

-1

I found a solution to create the correct null handling.

With NSwag it is possible to define your own templates. First set the template directory in your nswag.config and in this directory create a file Client.RequestUrl.liquid with the following content

let url_ = this.baseUrl + "/{{ operation.Path }}{% if operation.HasQueryParameters %}?{% endif %}";
{% for parameter in operation.PathParameters -%}
{%     if parameter.IsRequired -%}
if ({{ parameter.VariableName }} === undefined || {{ parameter.VariableName }} === null)
    throw new Error("The parameter '{{ parameter.VariableName }}' must be defined.");
{%     else -%}
if ({{ parameter.VariableName }} !== null && {{ parameter.VariableName }} !== undefined)
{%     endif -%}
{%     if parameter.IsDateOrDateTimeArray -%}
url_ = url_.replace("{{ "{" }}{{ parameter.Name }}}", encodeURIComponent({{ parameter.VariableName }}.map(s_ => s_ ? s_.toJSON() : "null").join()));
{%     elseif parameter.IsDateOrDateTime -%}
url_ = url_.replace("{{ "{" }}{{ parameter.Name }}}", encodeURIComponent({{ parameter.VariableName }} ? "" + {{ parameter.VariableName }}.toJSON() : "null"));
{%     elseif parameter.IsArray -%}
url_ = url_.replace("{{ "{" }}{{ parameter.Name }}}", encodeURIComponent({{ parameter.VariableName }}.join()));
{%     else -%}
url_ = url_.replace("{{ "{" }}{{ parameter.Name }}}", encodeURIComponent("" + {{ parameter.VariableName }}));
{%     endif -%}
{%     if parameter.IsOptional -%}
else
    url_ = url_.replace("/{{ "{" }}{{ parameter.Name }}}", "");
{%     endif -%}
{% endfor -%}
{% for parameter in operation.QueryParameters -%}
{%     if parameter.IsRequired -%}
{%         if parameter.IsNullable -%}
if ({{ parameter.VariableName }} === undefined)
    throw new Error("The parameter '{{ parameter.VariableName }}' must be defined.");
else
{%         else -%}
if ({{ parameter.VariableName }} === undefined || {{ parameter.VariableName }} === null)
    throw new Error("The parameter '{{ parameter.VariableName }}' must be defined and cannot be null.");
else
{%         endif -%}
{%     else -%}
{%         if parameter.IsNullable -%}
if ({{ parameter.VariableName }} !== undefined)
{%         else -%}
if ({{ parameter.VariableName }} === null)
    throw new Error("The parameter '{{ parameter.VariableName }}' cannot be null.");
else if ({{ parameter.VariableName }} !== undefined)
{%         endif -%}
{%     endif -%}
{%     if parameter.IsDateOrDateTimeArray -%}
    {{ parameter.VariableName }} && {{ parameter.VariableName }}.forEach(item_ => { url_ += "{{ parameter.Name }}=" + encodeURIComponent(item_ ? "" + item_.toJSON() : "null") + "&"; });
{%     elseif parameter.IsObjectArray -%}
    {{ parameter.VariableName }} && {{ parameter.VariableName }}.forEach((item, index) => {
        for (let attr in item)
            if (item.hasOwnProperty(attr)) {
                url_ += "{{ parameter.Name }}[" + index + "]." + attr + "=" + encodeURIComponent("" + (<any>item)[attr]) + "&";
            }
    });
{%     elseif parameter.IsDateOrDateTime -%}
    url_ += "{{ parameter.Name }}=" + encodeURIComponent({{ parameter.VariableName }} ? "" + {{ parameter.VariableName }}.toJSON() : "{{ QueryNullValue }}") + "&";
{%     elseif parameter.IsArray -%}
    {{ parameter.VariableName }} && {{ parameter.VariableName }}.forEach(item => { url_ += "{{ parameter.Name }}=" + encodeURIComponent("" + item) + "&"; });
{%     else -%}
    url_ += "{{ parameter.Name }}=" + ({{ parameter.VariableName }} !== null ? encodeURIComponent("" + {{ parameter.VariableName }}) : '') + "&";
{%     endif -%}
{% endfor -%}
url_ = url_.replace(/[?&]$/, "");

Thom Kiesewetter
  • 6,703
  • 3
  • 28
  • 41