christianhelle / apiclientcodegen

A collection of Visual Studio custom tool code generators for Swagger / OpenAPI specification files
http://bit.ly/restapicodegen
GNU General Public License v3.0
177 stars 23 forks source link

Support class name parameter in KiotaCodeGenerator #798

Closed faiteanu closed 5 months ago

faiteanu commented 8 months ago

Hello Christian, thanks for the nice library!

When using the Kiota generator, it is currently not possible to pass the -c ClassName parameter. That results in the default class name ApiClient being used, which is annoying if an application uses more than one REST service and they all have the same name ApiClient. The custom class name could be configured as a property of the input file in .csproj:

  <ItemGroup>
    <None Update="Swagger.json">
      <Generator>KiotaCodeGenerator</Generator>
      <GeneratedClassName>SpecialApiClient</GeneratedClassName>
    </None>
  </ItemGroup>

A GUI for this configuration is probably too much implementation effort.

christianhelle commented 8 months ago

Hi Fabian,

Thank you for your kind words and for taking the time to suggest this

I have mixed feelings about having configuration settings defined in the .csproj file, but I have toyed with the idea. I haven't tried giving it a shot yet but I'll experiment with it. Extending MSBuild is not my strong side either

What I do want to build next for this tool is to introduce a configuration file format. Something along the lines of having a configuration file called xxxopenapi.rapicgen inside the project folder containing something like this:

{
  "openApi": {
    "file": "https://petstore3.swagger.io/api/v3/openapi.json or the relative path to a local file",
    "spec": "the contents of an OpenAPI spec file instead of specifying a URI",
  }
  "generator": "kiota",
  "generatorVersion": "1.11.1",
  "generatorOptions": {
    "className": "SpecialApiClient",
    "optionXx": true,
    "optionYy": false
  }
}

generatorOptions would be used to specify options that are available to each code generator that this tool supports (NSwag, Refitter, OpenAPI Generator, Kiota, etc...)

This way users can have project-specific configuration options, instead of the global settings that it currently only supports

I would like to implement a Visual Studio custom tool that listens for changes to the file and re-generates the REST API client automagically.

All these things are non-trivial so it might take time.

What do you think @faiteanu ?

faiteanu commented 8 months ago

Hi Christian, thanks for the quick reply.

I can see your point regarding a custom file and I guess that would be better than a global configuration. Still, it is necessary to distinguish between project-general and file-specific settings, which should better not be mixed up.

I've based my opinion on the way the VS plugin works right now, which is to provide a Window to specify a URL and download that file to the project, adding a custom build tool like KiotaCodeGenerator.

So the build tool is specifically configured for the downloaded file through the Generator property in csproj. Other properties like GeneratedClassName or KiotaGeneratedClassName then naturally belong in the same place. https://learn.microsoft.com/en-us/visualstudio/extensibility/persisting-the-property-of-a-project-item?view=vs-2022 explains how to persist (and read) such properties. Your idea of a separate configuration file which points to an "openApi:file" URL is somewhat problematic, because it assumes that every developer and every build pipeline has access to that public URL. I would also argue that an API like github.com/**latest**/swagger.json might change over time and unexpectedly corrupt project code upon re-generation in a pipeline. The only two other properties I see in the suggested file are generator, which does not seem to offer any advantage over the file-specific Generator from csproj. I also doubt that generatorVersion offers a huge benefit, because it is generally advisable to use the latest version of any tool or library.

Just as another comment regarding the configuration file: if you insist on having it, please don't introduce a completely new file name extension .rapicgen, but use a double-extension ending in .json instead, e.g. myfile.rapicgen.json. It is then possible to define a schema for such a file and publish it on json-schema.org.

PS: due to the mentioned class name issue for multiple REST APIs and also #775, I have resorted to using kiota manually. As suggested in #175, which is from 2021, the file structure is clearer when you have separate files instead of mangling everything together. Weirdly, kiota generates some code with an [Obsolete] attribute, but that is not an issue within your project.

christianhelle commented 8 months ago

Hi @faiteanu

Thanks for all the detailed input!

I started looking into this and thanks for looking into how to read project item properties. That will come in handy. My first hurdle I how to get project item context from a file being processed by IVsSingleFileGenerator during Generate()

During this time the closest thing I have to identifying which project item is in use is the wszInputFilePath which is the full path of the input file

HRESULT IVsSingleFileGenerator::Generate(  
   [in] LPCOLESTR wszInputFilePath,  
   [in] BSTR bstrInputFileContents,  
   [in] LPCOLESTR wszDefaultNamespace,  
   [out] BYTE** rgbOutputFileContents,  
   [out] ULONG* pcbOutput,  
   [in] IVsGeneratorProgress* pGenerateProgress  
);

I usually work on this in the late hours but I got stuck last night and eventually got too sleepy to continue 😪 I'll give it another shot tonight

I will most likely continue with introducing a custom configuration file but I'll take your advice and use a double extension and publish the schema to json-schema.org. Having a configuration file like this will make my life easier when performing regression tests on this tool, using its CLI tool counterpart, rapicgen

The generatorVersion option that I mentioned is purely a suggestion by a long time user who is stuck on an older version of my extension because he is working on a large legacy project that requires an early OpenAPI Generator v6 which produces code that is rather different than what v7 produces. I originally wanted to implement using multiple versions of the code generators I support from a Visual Studio options page but that involved more work than I wanted to take on, and would be very tedious to test.

Anyway, I'll try to keep you posted on my progress with implementing code generator options in the csproj file

Hiller commented 8 months ago

I'm not that strong in creation of VS extensions but there's a nice VS feature called "Connected Services" https://learn.microsoft.com/en-us/visualstudio/azure/overview-connected-services?view=vs-2022 May be it makes sense to implement this extension like this? for example i found this https://github.com/OData/ODataConnectedService if i understood well, it seems you can store config as connected service metadata

christianhelle commented 8 months ago

@Hiller thanks for the suggestion

I did look into Visual Studio Connected Services in the beginning. This is how I discovered AutoRest many years ago.

My initial scenario is that the OpenAPI spec I worked with kept changing multiple times a day so the whole workflow of deleting code and then re-generating it got tiring very fast, which quickly led to me building my own Visual Studio extension

I could look into it again but this time from a different angle so that I use it as a UI with various options for generating a configuration file that will work together with the OpenAPI specifications so that every time changes happen on the OAS file, then the code will be re-generated using the same configuration it was initially created with. With something like that, we could present more complex options before generating code and persist and re-use them for future seamless re-generations

christianhelle commented 5 months ago

@faiteanu @Hiller I found a better implementation that uses the configuration file that Kiota itself generates called kiota-lock.json

I'm going for a setup where the extension detects whether the kiota-lock.json file exists, and if so, it uses it for generating the client code

Here's a screenshot: image

christianhelle commented 5 months ago

It is also possible to directly right click on the kiota-lock.json file and select Generate Kiota output

image