Skip to content

Conversation

@scottaj
Copy link
Contributor

@scottaj scottaj commented Aug 7, 2024

If a schema contains a date or date-time parameter in the url path, the typescript-fetch generator will expect that parameter to be passed as a JavaScript Date object. When serializing date objects for other parameter types, the generator serializes them as ISO8601 strings. For path parameters however, it is currently just stringifying the date object, leading to values like 'Tue Aug 06 2024 17:49:37 GMT-0600 (Mountain Daylight Time)' instead of '2024-08-06T23:49:37.781Z'. This causes issues with many webservers that expect the date to be in the ISO8601 format.

This pull request changes the behavior of path params to match the existing behavior of query and body params and use the ISO8601 format.

I didn't see a past issue for this exact problem, some relevant issues and past PRs I did find:

  • A recent change that did the same fix for url bodies
  • I think this might actually be a bug report of the issue from a couple years ago. The title mentions query params, but the example spec in the issue is a path param and would reproduce this bug

CC: @TiFu (2017/07) @taxpon (2017/07) @sebastianhaas (2017/07) @kenisteward (2017/07) @Vrolijkx (2017/09) @macjohnny (2018/01) @topce (2018/10) @akehir (2019/07) @petejohansonxo (2019/11) @amakhrov (2020/02) @davidgamero (2022/03) @mkusaka (2022/04)

PR checklist

  • Read the contribution guidelines.
  • Pull Request title clearly describes the work in the pull request and Pull Request description provides details about how to validate the work. Missing information here may result in delayed response from the community.
  • Run the following to build the project and update samples:
    ./mvnw clean package 
    ./bin/generate-samples.sh ./bin/configs/*.yaml
    ./bin/utils/export_docs_generators.sh
    
    (For Windows users, please run the script in Git BASH)
    Commit all changed files.
    This is important, as CI jobs will verify all generator outputs of your HEAD commit as it would merge with master.
    These must match the expectations made by your contribution.
    You may regenerate an individual generator by passing the relevant config(s) as an argument to the script, for example ./bin/generate-samples.sh bin/configs/java*.
    IMPORTANT: Do NOT purge/delete any folders/files (e.g. tests) when regenerating the samples as manually written tests may be removed.
  • File the PR against the correct branch: master (upcoming 7.6.0 minor release - breaking changes with fallbacks), 8.0.x (breaking changes without fallbacks)
  • If your PR is targeting a particular programming language, @mention the technical committee members, so they are more likely to review the pull request.

@scottaj
Copy link
Contributor Author

scottaj commented Aug 7, 2024

Hopefully this PR is helpful, I have currently run into this behavior breaking calls to an API.

A couple questions I had:

  1. I think it is correct to open this against master, and the recent very similar PR for form bodies was, but it is technically a breaking change if anyone was relying on the old date format, so should it be against the next major release instead?
  2. The petstore example doesn't have any endpoints that hit this use case, it was unclear to me if I should somehow update that to include one?

Copy link
Member

@macjohnny macjohnny left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for your contribution!

{{/hasFormParams}}
const response = await this.request({
path: `{{{path}}}`{{#pathParams}}.replace(`{${"{{baseName}}"}}`, encodeURIComponent(String(requestParameters['{{paramName}}']))){{/pathParams}},
path: `{{{path}}}`{{#pathParams}}{{#isDateTimeType}}.replace(`{${"{{baseName}}"}}`, encodeURIComponent(requestParameters['{{paramName}}'].toISOString())){{/isDateTimeType}}{{^isDateTimeType}}{{#isDateType}}.replace(`{${"{{baseName}}"}}`, encodeURIComponent(requestParameters['{{paramName}}'].toISOString().substring(0,10))){{/isDateType}}{{^isDateType}}.replace(`{${"{{baseName}}"}}`, encodeURIComponent(String(requestParameters['{{paramName}}']))){{/isDateType}}{{/isDateTimeType}}{{/pathParams}},
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how about

Suggested change
path: `{{{path}}}`{{#pathParams}}{{#isDateTimeType}}.replace(`{${"{{baseName}}"}}`, encodeURIComponent(requestParameters['{{paramName}}'].toISOString())){{/isDateTimeType}}{{^isDateTimeType}}{{#isDateType}}.replace(`{${"{{baseName}}"}}`, encodeURIComponent(requestParameters['{{paramName}}'].toISOString().substring(0,10))){{/isDateType}}{{^isDateType}}.replace(`{${"{{baseName}}"}}`, encodeURIComponent(String(requestParameters['{{paramName}}']))){{/isDateType}}{{/isDateTimeType}}{{/pathParams}},
path: `{{{path}}}`.replace(`{${"{{baseName}}"}}`,
{{#pathParams}}
{{#isDateTimeType}}
encodeURIComponent(requestParameters['{{paramName}}'].toISOString())
{{/isDateTimeType}}
{{^isDateTimeType}}
{{#isDateType}}
encodeURIComponent(requestParameters['{{paramName}}'].toISOString().substring(0,10))
{{/isDateType}}
{^isDateType}}
encodeURIComponent(String(requestParameters['{{paramName}}']))
{{/isDateType}}
{{/isDateTimeType}}
{{/pathParams}},

to simplify the template?

moreover, encodeURIComponent(requestParameters['{{paramName}}'].toISOString().substring(0,10)) is problematic because devs might be using a local date, and this converts the date to be in UTC. But at least this matches

'{{baseName}}': {{^required}}value['{{name}}'] == null ? undefined : {{/required}}({{#required}}{{#isNullable}}value['{{name}}'] == null ? null : {{/isNullable}}{{/required}}(value['{{name}}']{{#isNullable}} as any{{/isNullable}}).toISOString().substring(0,10)),

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can do the expanded style. I wasn't sure what the standards (if any are for the generated code, so I was trying to maintain the style of that. But your version makes the template more readable.

Regarding the iso string handling, I pretty much just copied the code above that is handling query params (line 140 of this file). So while I don't disagree about the UTC thing, I think if that is an issue it might need to be addressed as part of a larger change

I can add the null handling stuff you have, but are path params allowed to be nullable? I'll admit I don't know the spec well enough to be sure but that seems really weird. I suppose in that case though that putting in null as the path value is the correct behavior?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Regarding the nullable bit, my reading of the spec (both version 2 and version 3.1.0) is that a path parameter can't be null because the required property must be set to true: https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#fixed-fields-10

Determines whether this parameter is mandatory. If the parameter location is "path", this property is REQUIRED and its value MUST be true. Otherwise, the property MAY be included and its default value is false.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can also just add the null-safe operator „.?“ to be cautious

@macjohnny
Copy link
Member

@scottaj thanks for your contribution
Can you please re-generate the samples? See PR description

@scottaj
Copy link
Contributor Author

scottaj commented Aug 8, 2024

I did run those commands from the PR template. I don't believe any of the samples have a date as a path param, so running those did not result in any changes in git.

@macjohnny
Copy link
Member

please run

./mvnw clean package 
./bin/generate-samples.sh ./bin/configs/*.yaml
./bin/utils/export_docs_generators.sh

to re-generate the samples from your changed code.

Couldn't get handlebars to format the inline replaces in a sane way
without collapsing everything onto one very ugly line. This way keeps
some sane template formatting while still outputting workable code.
@scottaj
Copy link
Contributor Author

scottaj commented Aug 20, 2024

@macjohnny I updated the template and examples.

I ended up changing the template code structure because I could not get handlebars to format the inline replace calls in a nice way without collapsing the whole template section onto a single line like it was before.

@NiltiakSivad
Copy link

Thanks @scottaj for putting this together. I also need this change... @macjohnny any reason to not merge this change?

@macjohnny
Copy link
Member

oops, this one slipped my mind. @scottaj can you merge the most recent master and re-generate the samples please?

let urlPath = `{{{path}}}`;
{{#pathParams}}
{{#isDateTimeType}}
urlPath = urlPath.replace(`{${"{{baseName}}"}}`, encodeURIComponent((requestParameters['{{paramName}}'] as any).toISOString()));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please also check here whether it actually is a date object, i.e. instanceof Date

same below

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If it isn't a date what should we do? Obvious options seem to be to stringify whatever it is, or throw an error in the generated code

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, just to call out, none of the other parameter types are making that check now (query params, form params). Assume that if I add the check I should update all those to have the same handling?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah if its not a Date, just stringify. not sure this can happen in typescript-fetch, but just to be sure.
the other places (query params) should probably also have some safeguard, but ideally in a separate PR

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added type checking to date params: 373a34c

@scottaj
Copy link
Contributor Author

scottaj commented May 9, 2025

@macjohnny Merged with master, regenerated samples, and updated the Date checking

@macjohnny
Copy link
Member

somehow circleci failed

can you

merge the latest master again?

@scottaj
Copy link
Contributor Author

scottaj commented May 14, 2025

I merged master again. I am seeing this error for CircleCI:

Could not find a usable config.yml, you may have revoked the CircleCI OAuth app.

I haven't touched any CI configs, and i don't think I would be the one to give permission to that? So I'm not sure what to do.

@macjohnny macjohnny closed this May 16, 2025
@macjohnny macjohnny reopened this May 16, 2025
@macjohnny
Copy link
Member

macjohnny commented Jun 16, 2025

@scottaj sorry i dont know how to fix the circle ci config issue. can you please create a new PR, based on the latest master?

maybe you can also try the steps described in https://support.circleci.com/hc/en-us/articles/12504745606171-Why-am-I-seeing-the-Could-not-find-a-usable-config-yml-you-may-have-revoked-the-CircleCI-OAuth-app-message

@scottaj scottaj force-pushed the bugfix/typescript-fetch/dates-in-path-params branch from 17f6d99 to b24c0be Compare June 18, 2025 15:59
@scottaj
Copy link
Contributor Author

scottaj commented Jun 18, 2025

@macjohnny that was a good call. I followed the steps in that link and reset everything for CircleCI and now it seems to have worked.

@macjohnny macjohnny merged commit 88bc79e into OpenAPITools:master Jun 19, 2025
15 checks passed
@wing328 wing328 added this to the 7.14.0 milestone Jun 19, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants