Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FEATURE] Smithy should provide a way to group API operators in generated documentation #269

Closed
2 tasks
mteichtahl opened this issue Jan 20, 2023 · 5 comments · Fixed by #293
Closed
2 tasks
Labels

Comments

@mteichtahl
Copy link
Contributor

Describe the feature

Today, when documentation is generated from smithy it doesn't respect/understand the needs of documentation generation tools. For example, redoc, requires an x-tag for operator grouping - see https://redocly.com/docs/api-reference-docs/specification-extensions/x-tags/

Use Case

support a mechanism via custom tags or other implementation so that documentation generated is presentable and usable to customers.

Proposed Solution

No response

Other Information

No response

Acknowledgements

  • I may be able to implement this feature request
  • This feature might incur a breaking change

PDK version used

0.12.24

What languages will this feature affect?

Typescript, Java, Python

Environment details (OS name and version, etc.)

all

@cogwirrel
Copy link
Member

Had a quick look at this - unfortunately the x-tags property only seems to apply to schemas in redoc, not operations :(. Otherwise it would be possible to add these tags using the jsonAdd smithy build option, eg:

new SmithyApiGatewayTsProject({
  ...
  smithyBuildOptions: {
    projections: {
      openapi: {
        plugins: {
          openapi: {
            jsonAdd: {
              '/paths/~1hello/get/x-tags': ['foo', 'bar'],
            },
          },
        },
      },
    },
  },
});

It seems like redoc (and other openapi documentation generators) usually group operations by their tags property. Smithy can preserve tags from the @tags trait when generating openapi with the tags smithy build option. But this causes other issues unfortunately.

If you introduce tags, the code generators treat each tag as a separate "API", meaning a different client class is generated per-tag. This is problematic as it means the custom lambda handlers and operation lookup etc generated by the open-api-gateway package are also generated per-api, and at present the package assumes there is only one. It might be possible to update the codegen templates to address this but it needs a bit more investigation!

@cogwirrel
Copy link
Member

As an update here, updating the lambda handler wrapper generators to support tags is non-trivial since operations may be duplicated across multiple APIs (ie. can be tagged with more than one tag) - so we require some kind of de-duping of operations to make sure it works for all cases.

One approach is to generate the handler wrappers etc per API, then to collate and dedupe them to ensure only a single copy of each type/method/etc is exported per operation - while straightforward for TypeScript and probably Python, it would likely require some reflection magic for Java - and I'm not 100% sure it's possible.

There's an open feature request in openapi-generator which would simplify this a lot, and provide a simple way to generate code for operations over all APIs: OpenAPITools/openapi-generator#11843

I've submitted a first attempt at a PR to implement this feature OpenAPITools/openapi-generator#14568 so we'll see how that goes - if we can get it released we can then implement full support for the @tags trait.

As an intermediate quick win, it would be possible to at least implement support for single tags (ie. operations can be tagged with a single tag, or no tags) with openapi-generator as it is today. This would be a non-breaking change and would be at least a small improvement over breaking when tags are used at all, so I'll likely look at implementing this soon.

cogwirrel added a commit that referenced this issue Feb 1, 2023
This change adds support for tagging operations. Previously, tagging would cause broken lambda
handler wrappers etc to be generated since the CDK construct assumes a single OperationConfig, and
tagging APIs caused multiple to be generated. In this change, we always generate a single
OperationConfig, but iterate over all apis to  make sure all operations for all tags are included.
Note that this change only supports tagging each operation with zero or one tags, multiple tags will
cause duplicated code to be generated which will not build - support for multiple tags requires an
upstream change in openapi-generator.

re #269
cogwirrel added a commit that referenced this issue Feb 2, 2023
This change adds support for tagging operations. Previously, tagging would cause broken lambda
handler wrappers etc to be generated since the CDK construct assumes a single OperationConfig, and
tagging APIs caused multiple to be generated. In this change, we always generate a single
OperationConfig, but iterate over all apis to  make sure all operations for all tags are included.
Note that this change only supports tagging each operation with zero or one tags, multiple tags will
cause duplicated code to be generated which will not build - support for multiple tags requires an
upstream change in openapi-generator.

re #269
cogwirrel added a commit that referenced this issue Feb 3, 2023
This change adds support for tagging operations. Previously, tagging would cause broken lambda
handler wrappers etc to be generated since the CDK construct assumes a single OperationConfig, and
tagging APIs caused multiple to be generated. In this change, we always generate a single
OperationConfig, but iterate over all apis to  make sure all operations for all tags are included.
Note that this change only supports tagging each operation with zero or one tags, multiple tags will
cause duplicated code to be generated which will not build - support for multiple tags requires an
upstream change in openapi-generator.

re #269
cogwirrel added a commit that referenced this issue Feb 3, 2023
This change adds support for tagging operations. Previously, tagging would cause broken lambda
handler wrappers etc to be generated since the CDK construct assumes a single OperationConfig, and
tagging APIs caused multiple to be generated. In this change, we always generate a single
OperationConfig, but iterate over all apis to  make sure all operations for all tags are included.
Note that this change only supports tagging each operation with zero or one tags, multiple tags will
cause duplicated code to be generated which will not build - support for multiple tags requires an
upstream change in openapi-generator.

re #269
@cogwirrel
Copy link
Member

Single tags are now supported as of 0.13.5. So you can now tag your operations to group them into logical groups in generated documentation:

@tags(["foo"])
operation SayHello {
  ...
}

Multiple tags on an operation are not yet supported, as we're still tracking OpenAPITools/openapi-generator#14568

Note that API clients will be generated per tag, eg all operations tagged with foo will be part of FooApi in the typescript client.

On another note, it seems as though redoc's x-tags is not yet implemented Redocly/redoc#2148 , and the documentation mentions it only applies to "schemas" rather than "operations", so there may need to be some more work on the redoc side to enable grouping of operations in documentation without affecting the generated code.

@mteichtahl
Copy link
Contributor Author

mteichtahl commented Feb 3, 2023 via email

cogwirrel added a commit that referenced this issue Feb 15, 2023
This change adds support for tagging operations with multiple tags. This is achieved by using a new
feature of openapi-generator which will only consider the "first" (if any) tag for an operation
during code generation, ensuring that no duplicated code is generated. Note that the "first" tag for
OpenAPI-based projects is the one defined first in the list of tags associated with an operation.
Unfortunately Smithy 1.27.2 and below will sort tags alphabetically in the generated OpenAPI spec,
so the "first" tag is the lowest in the alphabet. This will be addressed in the next Smithy release.

fix #269
cogwirrel added a commit that referenced this issue Feb 15, 2023
This change adds support for tagging operations with multiple tags. This is achieved by using a new
feature of openapi-generator which will only consider the "first" (if any) tag for an operation
during code generation, ensuring that no duplicated code is generated. Note that the "first" tag for
OpenAPI-based projects is the one defined first in the list of tags associated with an operation.
Unfortunately Smithy 1.27.2 and below will sort tags alphabetically in the generated OpenAPI spec,
so the "first" tag is the lowest in the alphabet. This will be addressed in the next Smithy release.

fix #269
cogwirrel added a commit that referenced this issue Feb 15, 2023
This change adds support for tagging operations with multiple tags. This is achieved by using a new
feature of openapi-generator which will only consider the "first" (if any) tag for an operation
during code generation, ensuring that no duplicated code is generated. Note that the "first" tag for
OpenAPI-based projects is the one defined first in the list of tags associated with an operation.
Unfortunately Smithy 1.27.2 and below will sort tags alphabetically in the generated OpenAPI spec,
so the "first" tag is the lowest in the alphabet. This will be addressed in the next Smithy release.

fix #269
@cogwirrel
Copy link
Member

Another update here - I closed this as we now have full support for tags in the OpenAPI specification or Smithy model :)

The first tag will be used to determine which "API" an operation belongs in for code generation, and any subsequent tags are just used as a grouping mechanism by documentation generation tools.

One small caveat is that Smithy currently sorts tags alphabetically, so the "first" tag is the earliest tag in the alphabet. This will be addressed in the next Smithy release, but until then it's recommended to prefix your desired first tag with an underscore to make sure it's first.

If you're introducing tags but want to keep the generated clients the same (ie all operations remain in the DefaultApi class), you can just make sure you specify default as the first tag (this would be _default for smithy given the current Smithy limitation). eg:

@tags(["_default", "foo", "bar"])
operation SayHello {
  ...
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants