Skip to content

TypeScript client: serialize date-only parameters as yyyy-MM-dd instead of toISOString() - #5406

Open
salahBouragba wants to merge 1 commit into
RicoSuter:masterfrom
salahBouragba:fix/typescript-date-only-parameters
Open

salahBouragba wants to merge 1 commit into
RicoSuter:masterfrom
salahBouragba:fix/typescript-date-only-parameters

Conversation

@salahBouragba

Copy link
Copy Markdown

In the TypeScript client, a query, path or form parameter whose schema is { "type": "string", "format": "date" } is typed Date but serialized with toISOString() (or toJSON() for form parameters), so the request carries a full instant where the contract says a date-only string. Servers binding a date-only type refuse it: ASP.NET Core DateOnly answers an automatic 400 before the action runs, NodaTime LocalDate and Java LocalDate behave the same. DTO properties with the same schema were already handled correctly through NJsonSchema's formatDate(...).

This change makes parameters behave like properties: a date-only parameter is serialized as its calendar day, a date-time parameter is unchanged.

Before:

url_ += "startDate=" + encodeURIComponent(startDate ? "" + startDate.toISOString() : "") + "&";

After:

url_ += "startDate=" + encodeURIComponent(startDate ? formatDate(startDate) : "") + "&";

Closes #5405. Closes #2479. Closes #4295.

Why

Client.RequestUrl.liquid and Client.RequestBody.liquid branch on parameter.IsDateOrDateTime and emit parameter.GetDateTimeToString, which returns toISOString() for DateTimeType.Date without looking at the schema format. ParameterModelBase already exposes IsDate and IsDateArray separately from the date-time variants, so the templates now take those branches first:

  • TypeScriptParameterModel gains UseJsDate (dates are JavaScript Date objects, so formatDate() is used) and GetDateToString (the date-only call for MomentJS, DayJS and Luxon: format('YYYY-MM-DD'), toFormat('yyyy-MM-dd')), mirroring NJsonSchema's DataConversionGenerator for properties.
  • Client.RequestUrl.liquid: IsDateArray and IsDate branches for path and query parameters.
  • Client.RequestBody.liquid: the same for url-encoded form parameters, and an IsDate branch for FormData.
  • TypeScriptClientGenerator.GenerateFile adds the formatDate utility artifact when client code references it and no DTO artifact already brought it. NJsonSchema's TypeScriptGenerator.GenerateTypes only scans DTO artifacts, so a client with a date-only parameter and no date-only property would otherwise call a function that does not exist.

The String date type is not affected: such parameters are typed string, so IsDate is false and they are passed through as before.

Breaking changes

Generated clients change what they send for format: date parameters: the calendar day (2026-09-17, in the client's local time, as formatDate already does for properties) instead of an instant (2026-09-17T07:55:42.262Z). A server that declared format: date and binds a date-only type starts working; a server that declared format: date but binds a date-time keeps working, since a date-only string parses as midnight. Only a server that relied on receiving the time part behind a format: date declaration is affected, and its document was wrong.

Two additive changes to public surface: TypeScriptParameterModel.UseJsDate and TypeScriptParameterModel.GetDateToString. Custom templates that override Client.RequestUrl.liquid or Client.RequestBody.liquid keep their own behavior.

Verification

  • Breaking changes and migration steps documented, or "None" stated
  • Relevant builds and tests run, with results recorded: NSwag.CodeGeneration.TypeScript.Tests builds under the repository's warnings-as-errors settings and passes 63 of 63 tests, 4 of them new in DateParameterTests (path, query and array parameters with Date; formatDate emitted exactly once when a DTO property also needs it; DayJS formatting; url-encoded and multipart form parameters). Each generated client is also compiled with tsc through TypeScriptCompiler.AssertCompile.
  • Relevant snapshot or output diffs reviewed: no existing snapshot changed, which matches the test corpus having no format: date parameter. The new tests assert the exact generated lines rather than snapshots.
  • Documentation and samples updated no document in the repository describes how parameters are serialized; the wiki page on TypeScript client settings could mention that format: date parameters are sent as calendar days.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant