ferdikoomen / openapi-typescript-codegen

NodeJS library that generates Typescript or Javascript clients based on the OpenAPI specification
MIT License
2.94k stars 522 forks source link

Smart naming when generating services #314

Open andreujuanc opened 4 years ago

andreujuanc commented 4 years ago

Hi,

I'm consuming an API that has this path: /api/v1/management/organizations

This generates a OrganizationsService, which is fine, but there is no mention of management, or even v1 anywhere.

If we assume that the service name should be whatever comes after /api We could get V1ManagementOrganizationsService

It's horrible, but it works.

Another option is to generate those services in folders following the path, so:

/core
/models
/services
   /v1
       /management
            OrganizationsService.ts

v1 and management don't have anything so we could create just a placeholder object to have the reference to the children:

export class V1{
   public static Management: Management = Management
}

export class Management{
   public static Organizations: OrganizationsService = OrganizationsService 
}

//we have this already
export class OrganizationsService {
}

Following the previous snippet, I could now just V1.Management.Organizations.getAll()

I'm doing this currently by hand, and would be nice to automate it :)

Cheers

ferdikoomen commented 4 years ago

Hi @andreujuanc the path indeed has not much to do with the generated Services. There are two properties in the OpenAPI spec that control the generated names, the tags and operationId:

"paths": {
    "/api/v1/management/organizations/": {
        "get": {
            "tags": [
                "ManagementService"
            ],
            "operationId": "getAllOrganizations"
        }
    }
}

So this would generate a ManagementService.getAllOrganizations() call. There is no double nesting possible. If you use .Net or Java, then the tags are your controllers and the operations your methods.

We could add support for multiple tags, however they work differently than you would expect. Let's say you have the following spec:

"paths": {
    "/api/v1/management/organizations/": {
        "get": {
            "tags": [
                "Management",
                "Organizations"
            ],
            "operationId": "getAllOrganizations"
        }
    }
}

You maybe would expect that this would generate Management.Organizations.getAllOrganizations(), however that is not how tags work, see https://swagger.io/docs/specification/grouping-operations-with-tags/ for more info. What this will generate are two services with the same call, so you will get a ManagementService.getAllOrganizations() and a OrganizationsService.getAllOrganizations().

Cheers,

Ferdi

andreujuanc commented 4 years ago

Hi @ferdikoomen ,

Thanks for your quick response, very informative.

As of now, I have two projects, one of them we cannot make any change, so that's why I proposed the feature. We also have this problem:

"/api/v1/management/organizations": {
      "get": {
        "tags": [
          "organizations"
        ],
        "operationId": "organizations_GetAll",
     }
}    

As you can see, the tag and operationId have redundant text, and it would be cool to "cancel them out" .

So, for us the library works perfectly fine. We tested like 5 different client generators, and we liked this one the most. All except naming.

So is there any way we can "hook up" or configure the naming? maybe we can have openapitscodegen.js file somewhere with some callbacks? IDK

EDIT: In .Net we use NSwag to generate .Net clients, and there are 5 different naming options available, plus the ability to code it yourself. I wonder how hard it would be to do it similarly

ferdikoomen commented 4 years ago

Let me check what is possible, we are supporting some "x-" type properties like "x-enum", these are properties we can use for extending the spec. We can do something like "x-service-name" or indeed maybe some extension to inject custom logic for certain area's of the generator, like the openapitscodegen.js you are proposing. I will have a look at the NSwag naming options, is the one you are looking for one of the 5 options?

andreujuanc commented 4 years ago

We are using MultipleClientsFromPathSegmentsOperationNameGeneratorfrom https://github.com/RicoSuter/NSwag/blob/master/src/NSwag.CodeGeneration/OperationNameGenerators/MultipleClientsFromPathSegmentsOperationNameGenerator.cs

We tried it with TypescriptGenerator instead of C# one, but the generated code is too opinionated and did not fit with our project's dependencies.

yordis commented 3 years ago

x-service-name: string[] is what we used in the past.

natepappenhagen commented 3 years ago

@ferdikoomen Came here to say I would really like this feature. I've built some custom-generators using the openAPI library and it was super easy to just extend the SpringCodeGen and write some custom normalization logic for my method names. It's a game changer for me.