How to have different names for my API DTO's (based on the generator) with Nswag?
Asked Answered
W

3

6

I have a .NET 5.0 ASP.NET Core project and I am using Nswag to generate an API client. Let's say I have the following API model:

public class GetFooListResponseModel
{
    public string Bar { get; set; }
}

What I would like is 2 things. Let's start with the basic one.

  • How do I make the generated API Client's model name a different one than the one in my project? For example, I want the generated typescript model to be called Foo instead of GetFooListResponseModel.
  • Could I make them have different names based on the client it is generating? For example, for my C# Client I am completely fine with the existing model name, but the typescript one needs to be changed. If this is not possible it's no big deal, but it would be nice.

Thank you very much!

Wold answered 14/12, 2020 at 9:52 Comment(2)
I'm running into the same issue. Mine is creating names like this: "RestResponseOfAuthResponseModel". Where you ever able to come up with a solution?Retread
@Retread Sadly no, I have not looked into it more. But you posted a comment on Santhosh's answer saying you things did differently and with a few extra steps. Could you post your answer as well, please? I am very curious!Wold
L
5

You can use SchemaNameGenerator to customise the model name. You can refer shadowsheep's answer . To generate completely new Model name you can use CustomeAttribute with SchemaNameGenerator.

public class ClientModelAttribute : Attribute
{
    public string Name { get; set; }
    public ClientModelAttribute(string name)
    {
        Name = name;
    }
}

  internal class CustomSchemaNameGenerator : ISchemaNameGenerator
{
    public string Generate(Type type)
    {
        var attrs = type.GetCustomAttributes(typeof(ClientModelAttribute),true);

        foreach (var attr in attrs)
        {
            if(attr is ClientModelAttribute)
            {
                ClientModelAttribute clientModel = attr as ClientModelAttribute;
                return clientModel.Name;
            }
        }

        return type.FullName;
    }
}

Model Class with CustomAttribute

[ClientModel("Foo")]
public class WeatherForecast
{
    public DateTime Date { get; set; }

    public int TemperatureC { get; set; }

    public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);

    public string Summary { get; set; }
}

update ConfigureServices

services.AddSwaggerDocument(cfg => { cfg.SchemaNameGenerator = new CustomSchemaNameGenerator(); });

swagger.json

 "paths": {
"/WeatherForecast": {
  "get": {
    "tags": [
      "WeatherForecast"
    ],
    "operationId": "WeatherForecast_Get",
    "responses": {
      "200": {
        "x-nullable": false,
        "description": "",
        "schema": {
          "type": "array",
          "items": {
            "$ref": "#/definitions/Foo"
          }
        }
      }
    }
  }
}
Lupulin answered 18/10, 2021 at 12:43 Comment(2)
ClientModelAttribute is not needed. The DefaultTypeNameGenerator uses the JsonSchemaAttribute to get the custom type name. I created a new super class that inherits from DefaultTypeNameGenerator and and overridden Generate to do a few extra steps.Retread
I like this answer, although it isn't perfect.. for example, how would I differentiate between my C# generator and TS operator with nswag? I'm starting to feel like this is not possible.Wold
F
0

Sometimes, the best solution is the simplest. Try creating a windows/message asking the user what they would like their module name to be that would trigger once the program starts?

Free answered 19/10, 2021 at 20:26 Comment(0)
R
-1

You can simply create a injectable service called 'FooService' for communicating with backend services using HTTP Request. Specify the model/class (you can create any name you want) being returned from your API in getFooListResponse(). The naming not necessary must be the same with GetFooListResponseModel, as long the attributes and its data type of the model/class are same.

foo.service.ts

@Injectable()
export class FooService 
{
  constructor(
  protected http: HttpClient
  ) {}

  getFooListResponse() {
    const endpointUrl = "myEndpointUrl";
    return this.http.get<Foo>(endpointUrl);
  }
}

foo.model.ts

export class Foo {
    public Bar: string;
}
Renita answered 18/10, 2021 at 1:53 Comment(1)
The point of my question is that the service and model are auto generated so you do not need to create a FooService or Foo model anymore. Your answer is not related to my question, sadly.Wold

© 2022 - 2024 — McMap. All rights reserved.