Skip to content

Conversation

@MrScottyTay
Copy link

For #672


IdentifierUtils.Counted() now removes the NSwag appended numbers if parent is not null.
RefitMultipleInterfaceByTagGenerator.GenerateCode() now has the interfaceName outside of the op loop scope, after the first in a group, all subsequent op loops it would reset to null, meaning no parent was supplied to IdentifierUtils.Counted().
dynamicQuerystringParameterType has the interfaceName at the start to prevent clashes.
Updated MultipleInterfacesByTagsTests' spec to be able to test these changes.

At the moment not all tests pass due to the changes I made to the dynamicQuerystringParameterType specifically, and I would like to put in some tests to ensure that IdentifierUtils.Counted() does still count correctly when both multiple interfaces by tag generations and for single interface generations.

The test that currently fails is ApizrTests.Generates_Dynamic_Querystring_Parameters_ByTag.


Before continuing I was hoping for some feedback to see if this was a suitable method.

From testing and debugging, the numbers are initially appended by NSwag, before the IdentifierUtils.Counted() method is even reached (hence the stripping of numbers at the end of the operationId in my changes). I was hoping to maybe find a way to stop that from happening at that end, but I couldn't figure out exactly where I could do it and saw that there was already a fallback with the IdentifierUtils.Counted() so decided it was suitable to workaround it the way I have done.

Since the records for the query params are not within each given interface, a clash can still occur due to the changes I made with IdentifierUtils.Counted(). I went with prepending them with the Tag used for the interface since the point of my changes was to try and remove the numbers appended to method names, and felt this ideology would then clash with allowing these to still have numbers on the end. But let me know your opinions on whether or not this was the right move or not.

If this is the way to go then I would have to change the spec in ApizrTests.Generates_Dynamic_Querystring_Parameters_ByTag too and add in a few more tests like I want to do with MultipleInterfacesByTagsTests as well.


However I'm wondering if this behaviour should be hard coded as I have implemented it so far or be another option in the config.

…arent is not null. RefitMultipleInterfaceByTagGenerator.GenerateCode() now has the interfaceName outside of the op loop scope, after the first in a group, all subsequent op loops it would reset to null, meaning no parent was supplied to IdentifierUtils.Counted(). dynamicQuerystringParameterType has the InterfaceName at the start to prevent clashes. Updated MultipleInterfacesByTagsTests' spec to be able to test these changes.
@coderabbitai
Copy link
Contributor

coderabbitai bot commented May 16, 2025

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@MrScottyTay MrScottyTay changed the title IdentifierUtils.Counted() now removes the NSwag appended numbers if p… Interface-scoped OperationIds May 16, 2025
@sonarqubecloud
Copy link

@christianhelle christianhelle requested a review from Copilot May 19, 2025 21:40
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR addresses issue #672 by refining how operationIds are handled in an interface-scoped context, specifically by stripping off NSwag-appended numbers and adjusting the dynamic querystring parameter naming. Key changes include:

  • Removing numeric suffixes from operationIds in IdentifierUtils.Counted() when a parent is provided.
  • Moving the interfaceName initialization outside the operation loop in RefitMultipleInterfaceByTagGenerator to maintain scope.
  • Updating tests in MultipleInterfacesByTagsTests to validate the new naming conventions.

Reviewed Changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.

File Description
src/Refitter.Tests/Examples/MultipleInterfacesByTagsTests.cs Test updates to reflect new operationId and dynamic querystring parameter naming.
src/Refitter.Core/RefitMultipleInterfaceByTagGenerator.cs Adjusted variable scope for interfaceName and dynamic querystring parameter generation.
src/Refitter.Core/IdentifierUtils.cs Updated regex-based stripping of numeric suffixes when a parent is present.

Dictionary<string, string> interfacesNamesByGroup = new();

foreach (var kv in byGroup)
{
Copy link

Copilot AI May 19, 2025

Choose a reason for hiding this comment

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

[nitpick] Consider adding a clarifying comment to explain why interfaceName is declared outside of the loop and initialized with null!, as this could improve readability and maintainability.

Suggested change
{
{
// Declaring interfaceName outside the inner loop to ensure it is accessible
// for the current group. It is initialized with null! because it is guaranteed
// to be assigned a value (via GetInterfaceName) before being used.

Copilot uses AI. Check for mistakes.

var operationName = GetOperationName(interfaceName, op.PathItem.Key, operations.Key, operation);
var dynamicQuerystringParameterType = operationName + "QueryParams";
var dynamicQuerystringParameterType = kv.Key.CapitalizeFirstCharacter() + operationName + "QueryParams";
Copy link

Copilot AI May 19, 2025

Choose a reason for hiding this comment

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

It would be beneficial to document the naming scheme for dynamic querystring parameter types to clarify why the group key is prepended and how it prevents naming clashes.

Copilot uses AI. Check for mistakes.
@christianhelle christianhelle self-assigned this May 19, 2025
@christianhelle christianhelle added the enhancement New feature, bug fix, or request label May 19, 2025
@christianhelle christianhelle self-requested a review May 19, 2025 22:01
@MrScottyTay
Copy link
Author

This isn't ready to be merged yet, mind. Was waiting on some feedback on my approach before I finalise it. Like whether or not this should default or should it be a config flag to prevent breaking changes.

@christianhelle
Copy link
Owner

This isn't ready to be merged yet, mind. Was waiting on some feedback on my approach before I finalise it. Like whether or not this should default or should it be a config flag to prevent breaking changes.

Sorry for the delay. I pulled the branch to look into it in a bit more detail. I love the simplicity and the fact that there are so few changes to implement this. From what I've seen so far, this looks good.

Unfortunately, to not break the experience for existing users, the changes here should not be the default behavior..

I have a suite of smoke tests that run Refitter against a larger set of OpenAPI specification examples. It takes some time to run (close to 10 minutes on my 16-core Ryzen 9 9950X3D with 192GB of RAM). This is what the build pipeline runs for PR verification. To run it locally, use the test/smoke-tests.ps1 powershell script

@MrScottyTay
Copy link
Author

Thanks for the feedback.

I'll look into implementing these changes as an optional config setting and I'll revert the tests I modified and create a new set of tests that are just for testing this new setting.

@kirides
Copy link
Contributor

kirides commented Jun 16, 2025

This feature seems non-spec compliant, as OperationIds are required to be document-wide unique values

Openapi 3.0 (source https://swagger.io/docs/specification/v3_0/paths-and-operations/)

operationId

operationId is an optional unique string used to identify an operation. If provided, these IDs must be unique among all operations described in your API.

OpenApi 3.1 (source https://swagger.io/specification/)

operationId - string
Unique string used to identify the operation. The id MUST be unique among all operations described in the API. The operationId value is case-sensitive. Tools and libraries MAY use the operationId to uniquely identify an operation, therefore, it is RECOMMENDED to follow common programming naming conventions.

@christianhelle
Copy link
Owner

This feature seems non-spec compliant, as OperationIds are required to be document-wide unique values

Thanks for pointing this out @kirides. Most backend tooling should complain when generating a non-compliant spec, and things like SwaggerUI or Scalar won't be able to work with it either.

That said, since this is client code generation tool, I'm actually okay with features that are not fully compliant with the OpenAPI specifications, which is also why I use NSwag for parsing the OAS document instead of the Microsoft OpenAPI tooling which is much more strict. NSwag let's you get away with OAS documents that contain errors. I can only hope and assume that the paths, parameters, and schemas are correct in the OAS document are correct, and things like operation ids, tags, summaries, and descriptions can be used as hints for function naming

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

Labels

enhancement New feature, bug fix, or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants