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

C# client does not generate methods when schema is the "any-type" scheme #3536

Closed
iozcelik opened this issue Oct 22, 2023 · 3 comments · Fixed by #3652
Closed

C# client does not generate methods when schema is the "any-type" scheme #3536

iozcelik opened this issue Oct 22, 2023 · 3 comments · Fixed by #3652
Assignees
Labels
generator Issues or improvements relater to generation capabilities. type:bug A broken experience WIP
Milestone

Comments

@iozcelik
Copy link
Contributor

iozcelik commented Oct 22, 2023

In my project, I generate C# client for Atlassian OpenAPI. However one of response has the "any-type" scheme ({}).

Example part of OpenAPI file:

responses:
  '200':
    description: Returned if the worklog property is updated.
    content:
      application/json:
        schema: {}

So I debug the source code of Kiota and find the reason. In response content has schema but actually it is not any type. The GetExecutorMethodReturnType method in KiotaBuilder has an if statement and the statement acts like schema is not null. So it returns (null,null), the code throw exception at CreateOperationMethods method while getting instance of CodeMethod.

I add an else statement like this:

if (modelType is not null && config.IncludeBackwardCompatible && config.Language is GenerationLanguage.CSharp or GenerationLanguage.Go && modelType.Name.EndsWith(suffix, StringComparison.Ordinal)){
// modelType is null so it goes to else
}
else
{
    string returnType;
    if (operation.Responses.Any(static x => noContentStatusCodes.Contains(x.Key)))
        returnType = VoidType;
    else if (operation.Responses.Any(static x => x.Value.Content.ContainsKey(RequestBodyPlainTextContentType)))
        returnType = "string";
    else
        returnType = "binary";
    return (new CodeType { Name = returnType, IsExternal = true, }, null);
}

And it works. I am not an OpenAPI expert so I am not sure how Kiota acts for "any-type" schema.

My test code:

    [Fact]
    public async Task AnyTypeResponse()
    {
        var tempFilePath = Path.Combine(Path.GetTempPath(), Path.GetTempFileName());
        await using var fs = await GetDocumentStream(@"openapi: 3.0.1
info:
  title: The Jira Cloud platform REST API
externalDocs:
  description: Find out more about Atlassian products and services.
  url: http://www.atlassian.com
paths:
  /issueLink:
    post:
      tags:
        - Issue links
      summary: Create issue link
      operationId: linkIssues
      parameters: []
      requestBody:
        description: The issue link request.
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/LinkIssueRequestJsonBean'
        required: true
      responses:
        '201':
          description: Returned if the request is successful.
          content:
            application/json:
              schema: {}
        '400':
          description: no desc.
        '401':
          description: no desc.
        '404':
          description: no desc.
      deprecated: false
components:
  schemas:
    Comment:
      type: object
      properties:
        body:
          description: >-
            The comment text in [Atlassian Document
            Format](https://developer.atlassian.com/cloud/jira/platform/apis/document/structure/).
        created:
          type: string
          format: date-time
          readOnly: true
        id:
          type: string
          readOnly: true
        jsdAuthorCanSeeRequest:
          type: boolean
          readOnly: true
        jsdPublic:
          type: boolean
          readOnly: true
        renderedBody:
          type: string
          readOnly: true
        self:
          type: string
          description: The URL of the comment.
          readOnly: true
        updated:
          type: string
          description: The date and time at which the comment was updated last.
          format: date-time
          readOnly: true
      additionalProperties: true
      description: A comment.
    IssueLinkType:
      type: object
      properties:
        id:
          type: string
        inward:
          type: string
        name:
          type: string
        outward:
          type: string
        self:
          type: string
          format: uri
          readOnly: true
      additionalProperties: false
    LinkIssueRequestJsonBean:
      required:
        - inwardIssue
        - outwardIssue
        - type
      type: object
      properties:
        comment:
          $ref: '#/components/schemas/Comment'
        inwardIssue:
          $ref: '#/components/schemas/LinkedIssue'
        outwardIssue:
          $ref: '#/components/schemas/LinkedIssue'
        type:
          $ref: '#/components/schemas/IssueLinkType'
      additionalProperties: false
    LinkedIssue:
      type: object
      properties:
        fields:
          description: The fields associated with the issue.
          readOnly: true
        id:
          type: string
          description: The ID of an issue. Required if `key` isn't provided.
        key:
          type: string
          description: The key of an issue. Required if `id` isn't provided.
        self:
          type: string
          description: The URL of the issue.
          format: uri
          readOnly: true
      additionalProperties: false
      description: The ID or key of a linked issue.");
        var mockLogger = new Mock<ILogger<KiotaBuilder>>();
        var builder = new KiotaBuilder(mockLogger.Object, new GenerationConfiguration { ClientClassName = "Graph", OpenAPIFilePath = tempFilePath, IncludeAdditionalData = false }, _httpClient);
        var document = await builder.CreateOpenApiDocumentAsync(fs);
        var node = builder.CreateUriSpace(document);
        var codeModel = builder.CreateSourceModel(node);
        Assert.NotNull(codeModel);
        var rbClass = codeModel.FindChildByName<CodeClass>("issueLinkRequestBuilder");
        Assert.NotNull(rbClass);
        var postMethod = rbClass.FindChildByName<CodeMethod>("Post", false);
        Assert.NotNull(postMethod);
        var linkIssueRequestJsonBeanClass = codeModel.FindChildByName<CodeClass>("LinkIssueRequestJsonBean");
        Assert.NotNull(linkIssueRequestJsonBeanClass);
    }
@github-project-automation github-project-automation bot moved this to Todo in Kiota Oct 22, 2023
@baywet baywet self-assigned this Oct 23, 2023
@baywet baywet added this to the Backlog milestone Oct 23, 2023
@baywet
Copy link
Member

baywet commented Oct 23, 2023

Hi @iozcelik,
Thanks for using kiota and for reaching out.

I'm not sure I understand what is the current behaviour and the expected one?

Are you saying that for the description you've provided, kiota throws and exception? it should set the return type to "binary" instead for the time being (stream).

Are you expecting something different than stream in that example?

@iozcelik
Copy link
Contributor Author

iozcelik commented Oct 23, 2023

Hi @baywet ,

I'm not sure I understand what is the current behaviour and the expected one?

I am expecting that Kiota should create a post method with LinkIssueRequestJsonBean parameter. However it throws exception and not create post method.

Are you saying that for the description you've provided, kiota throws and exception? it should set the return type to "binary" instead for the time being (stream).

Yes, when I add the else statement to my local Kiota code. It works and generate post method with LinkIssueRequestJsonBean parameter. However, I am not sure about return type. I see an example in code if the content looking like that application/json: {}, you return "binary". Therefore the mean is same with that case.

If you debug my test code, you would see the problem.

The exception:

warn: Kiota.Builder.KiotaBuilder[0]
      Could not create method for linkIssues in \rest\api\3\issueLink because the schema was invalid
      Kiota.Builder.Exceptions.InvalidSchemaException: Operation is not valid due to the current state of the object.
         at Kiota.Builder.KiotaBuilder.CreateOperationMethods(OpenApiUrlTreeNode currentNode, OperationType operationType, OpenApiOperation operation, CodeClass parentClass) in D:\a\1\s\src\Kiota.Builder\KiotaBuilder.cs:line 1349

@baywet
Copy link
Member

baywet commented Oct 23, 2023

Thanks for the additional information.

Until we design and solve for #2548, the generator should map such cases to binary.

Is this something you'd like to submit a pull request for?

@baywet baywet added type:bug A broken experience generator Issues or improvements relater to generation capabilities. and removed question Needs: Attention 👋 labels Oct 23, 2023
@baywet baywet assigned iozcelik and unassigned baywet Oct 23, 2023
@baywet baywet modified the milestones: Backlog, Kiota v1.8 Oct 23, 2023
iozcelik added a commit to iozcelik/kiota that referenced this issue Nov 5, 2023
- Add culture invariant to convert of float values
baywet added a commit that referenced this issue Nov 6, 2023
Fixed #3536 and also converting float to string
@github-project-automation github-project-automation bot moved this from Todo to Done in Kiota Nov 6, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
generator Issues or improvements relater to generation capabilities. type:bug A broken experience WIP
Projects
Archived in project
Development

Successfully merging a pull request may close this issue.

3 participants