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

[Bug]: sharedRoute openapi operationId issue #5513

Open
4 tasks done
csaba-veezla opened this issue Jan 7, 2025 · 2 comments
Open
4 tasks done

[Bug]: sharedRoute openapi operationId issue #5513

csaba-veezla opened this issue Jan 7, 2025 · 2 comments
Assignees
Labels
emitter:openapi3 Issues for @typespec/openapi3 emitter feature New feature or request needs-area

Comments

@csaba-veezla
Copy link

Describe the bug

We have a use case where you can create assets in our system; the source of an asset can differ.
So for the same endpoint, we support both "multipart/form-data" and "application/json" as content types.

The two operations are slightly different from each other, so we are leveraging the @sharedRoute operator.
The issue comes from the open API emitter. It concatenates the operationIds, and the resulting operationId is rarely unusable for the client code generation.

operationId: operations.map((op) => resolveOperationId(program, op.operation)).join("_"),

As you can see in the playground, it will result in the following shared operationId: Assets_createAsset_Assets_createAssetWithUpload or createAsset_createAsset if you had set the individual operations to createAsset.
Afterward, this will result in something similar in the generated code as well.

I see 2 solutions to this problem:

  • Either it should run a unique on that operations.map, so if all the shared operations have the same operationId, the shared id will be the same.
  • Alternatively, it checks if the shared operations have a provided operationId and it joins the the ones that have some, or if there is none, it generates the one that it does right now (mostly will result in the same json as it does now, backward compatible)

Reproduction

I tried to reduce the code to the minimum, but I couldn't make the operationId decorator work, it should be part of the @typespec/openapi3 lib, so I'm not sure, what I am missing:

playground

Checklist

@csaba-veezla csaba-veezla added the bug Something isn't working label Jan 7, 2025
@csaba-veezla csaba-veezla changed the title [Bug]: sharedRoute openapi issues [Bug]: sharedRoute openapi operationId issue Jan 7, 2025
@markcowl markcowl added the emitter:openapi3 Issues for @typespec/openapi3 emitter label Jan 7, 2025
@markcowl markcowl added feature New feature or request and removed bug Something isn't working labels Jan 8, 2025
@markcowl markcowl added the needs-info Mark an issue that needs reply from the author or it will be closed automatically label Jan 8, 2025
@markcowl markcowl self-assigned this Jan 8, 2025
@wanlwanl
Copy link
Member

wanlwanl commented Jan 10, 2025

Hi @csaba-veezla, thank you for reaching out!
Regarding @operationid, it's in the OpenAPI library, it appears in the fourth line of the playground example below.
Playground

From my understanding, you are expecting to achieve the desired result both when the @operationId decorator is included and when it is not. However, based on your description, I am unable to fully grasp what your expected outcome is.

Could you please provide more details on your expectations for the generated results in the following scenarios?

  1. When shared routes do not include the @operationId decorator.
  2. When shared routes partially include the @operationId decorator.
  3. When all shared routes include the @operationId decorator.
    This information will help us assist you more effectively. Looking forward to your clarification!

@csaba-veezla
Copy link
Author

Ohh, so I should have imported @typespec/openapi as well, I will do that the next time.

I'll try my best to elaborate.
The base issue is, I want my shared operation ID to be something I set.
So If I have a shared route with operationA, operationB, and operationC, I want to be able to set their shared
operation ID to something like myOperation.

Since I have proposed two distinct solutions to the issue, I'll provide two separate answers, to address your questions.

1st Solution: "Unique ID" (Everyone contributes, but it's like brainstorming—each unique idea counts only once, the first time)

  1. No decorator
    The shared operation ID should be generated as it is now.

  2. Partially decorated
    a. Let's assume operationA and operationB have the @operationId("myOperation") decorator, while operationC
    does not. In this case, the shared operation ID will look like this:
    myOperation_<generatedOperationIdForC>.

    operationA and operationB provide only a single myOperation to the shared ID.
    If there were an operationD after operationC with @operationId("myOperation"),
    the shared operation ID would still be myOperation_<generatedOperationIdForC>.

    b. Let's assume operationA and operationB use their names as decorators, while operationC does not. In this
    case, the shared operation ID will look like this:
    operationA_operationB_<generatedOperationIdForC>.

  3. All decorated
    a. Let's assume operationA and operationB have the @operationId("myOperation") decorator, while operationC
    has a @operationId("cOperation") decorator. The shared operation ID will be:
    myOperation_cOperation.

    b. Let's assume all operations have the @operationId("myOperation") decorator. The shared operation ID will be:
    myOperation.

    This is how this solution addresses the initial issue.

2nd Solution: "Has Operation ID" (Only contributors are recognized if any exists)

  1. No decorator
    The shared operation ID should be generated as it is now.

  2. Partially decorated
    a. Let's assume operationA and operationB have the @operationId("myOperation") decorator, while operationC does not. In this case, the shared operation ID will be:
    myOperation_myOperation.

    operationC does not contribute to the ID.

    b. Let's assume operationA and operationB use their names as decorators, while operationC does not. In this case, the shared operation ID will be:
    operationA_operationB.

    c. Let's assume only operationA has the @operationId("myOperation") decorator, while operationB and operationC do not. In this case, the shared operation ID will be:
    myOperation.

    This is how this solution addresses the initial issue.

  3. All decorated
    a. Let's assume operationA and operationB have the @operationId("myOperation") decorator, while operationC has a @operationId("cOperation") decorator. The shared operation ID will be:
    myOperation_myOperation_cOperation.

    b. Let's assume all operations have the @operationId("myOperation") decorator. The shared operation ID will be:
    myOperation_myOperation_myOperation.

While I am not entirely familiar with the code of the emitter, it seems to me that the 1st solution (unique) would be
easier to implement.

I hope I was able to answer the questions clearly, convey the issue effectively, and present the proposed solutions more comprehensively.

@microsoft-github-policy-service microsoft-github-policy-service bot added needs-area and removed needs-info Mark an issue that needs reply from the author or it will be closed automatically labels Jan 13, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
emitter:openapi3 Issues for @typespec/openapi3 emitter feature New feature or request needs-area
Projects
None yet
Development

No branches or pull requests

3 participants