Currently I am consuming an api which uses the OpenApi spec which is generated using Swagger.
In the api there are multiple endpoints, for example /Customer/GetById
and /License/GetById
.
This causes the code generation to generate a client which justs lists the methods using numbers.
It would be better to have a method named LicenseGetByIdAsync(...)
and CustomerGetByIdAsync(...)
. (Or anything to distinguish them)
(how) can I achieve this using my nswag config? I can also change the OpenApi json generation
My nswag file looks like this:
{
"runtime": "Default",
"defaultVariables": null,
"documentGenerator": {
"fromDocument": {
"json": "$(InputSwagger)",
"url": "http://redocly.github.io/redoc/openapi.yaml",
"output": null
}
},
"codeGenerators": {
"openApiToCSharpClient": {
"clientBaseClass": null,
"configurationClass": null,
"generateClientClasses": true,
"generateClientInterfaces": true,
"injectHttpClient": true,
"disposeHttpClient": false,
"protectedMethods": [],
"generateExceptionClasses": true,
"exceptionClass": "$(ClientName)Exception",
"wrapDtoExceptions": true,
"useHttpClientCreationMethod": false,
"httpClientType": "System.Net.Http.HttpClient",
"useHttpRequestMessageCreationMethod": false,
"useBaseUrl": false,
"generateBaseUrlProperty": true,
"generateSyncMethods": false,
"exposeJsonSerializerSettings": true,
"clientClassAccessModifier": "public",
"typeAccessModifier": "public",
"generateContractsOutput": false,
"contractsNamespace": null,
"contractsOutputFilePath": null,
"parameterDateTimeFormat": "s",
"generateUpdateJsonSerializerSettingsMethod": true,
"serializeTypeInformation": false,
"queryNullValue": "",
"className": "$(ClientName)Client",
"operationGenerationMode": "MultipleClientsFromOperationId",
"additionalNamespaceUsages": [],
"additionalContractNamespaceUsages": [],
"generateOptionalParameters": false,
"generateJsonMethods": true,
"enforceFlagEnums": false,
"parameterArrayType": "System.Collections.Generic.IEnumerable",
"parameterDictionaryType": "System.Collections.Generic.IDictionary",
"responseArrayType": "System.Collections.Generic.ICollection",
"responseDictionaryType": "System.Collections.Generic.IDictionary",
"wrapResponses": false,
"wrapResponseMethods": [],
"generateResponseClasses": true,
"responseClass": "$(ClientName)Response",
"namespace": "$(ClientNamespace)",
"requiredPropertiesMustBeDefined": false,
"dateType": "System.DateTimeOffset",
"jsonConverters": null,
"anyType": "object",
"dateTimeType": "System.DateTimeOffset",
"timeType": "System.TimeSpan",
"timeSpanType": "System.TimeSpan",
"arrayType": "System.Collections.Generic.ICollection",
"arrayInstanceType": "System.Collections.ObjectModel.Collection",
"dictionaryType": "System.Collections.Generic.IDictionary",
"dictionaryInstanceType": "System.Collections.Generic.Dictionary",
"arrayBaseType": "System.Collections.ObjectModel.Collection",
"dictionaryBaseType": "System.Collections.Generic.Dictionary",
"classStyle": "Poco",
"generateDefaultValues": true,
"generateDataAnnotations": true,
"excludedTypeNames": [],
"excludedParameterNames": [],
"handleReferences": false,
"generateImmutableArrayProperties": false,
"generateImmutableDictionaryProperties": false,
"jsonSerializerSettingsTransformationMethod": null,
"inlineNamedArrays": false,
"inlineNamedDictionaries": false,
"inlineNamedTuples": true,
"inlineNamedAny": false,
"generateDtoTypes": true,
"templateDirectory": null,
"typeNameGeneratorType": null,
"propertyNameGeneratorType": null,
"enumNameGeneratorType": null,
"serviceHost": null,
"serviceSchemes": null,
"output": "$(GeneratedSwaggerClientFile)"
}
}
}
and my swagger file looks like this
{
"openapi": "3.0.1",
"info": {
"title": "ConfigurationManagement.Api",
"version": "v1"
},
"paths": {
"/api/customer/getbyid/{id}": {
"get": {
"tags": [
"Customer"
],
"summary": "Gets an Customer by the id",
"parameters": [
{
"name": "id",
"in": "path",
"description": "The id of the customer.",
"required": true,
"schema": {
"type": "string",
"format": "uuid"
}
}
],
"responses": {
"200": {
"description": "Success",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/CustomerDtoSingleItemResultDto"
}
}
}
}
}
}
},
...
"/api/license/getbyid/{id}": {
"get": {
"tags": [
"License"
],
"summary": "Gets an License by the id",
"parameters": [
{
"name": "id",
"in": "path",
"description": "The id of the license.",
"required": true,
"schema": {
"type": "string",
"format": "uuid"
}
}
],
"responses": {
"200": {
"description": "Success",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/LicenseDtoSingleItemResultDto"
}
}
}
}
}
}
},
...
}
}
I have fixed the issue in two steps:
public class OperationControllerPrefixFilter : IOperationFilter
{
public void Apply(OpenApiOperation operation, OperationFilterContext context)
{
// for example: api/customer/list will become [] {'customer', 'list'}
var arr = context.ApiDescription.RelativePath
.Split('/')
.Skip(1)
.Take(2)
.ToArray();
// becomes customer_list
operation.OperationId = $"{arr[0]}_{arr[1]}";
Debug.WriteLine(operation.OperationId);
}
}
operationGenerationMode
from MultipleClientsFromOperationId
to SingleClientFromOperationId
in the nswag of the consuming application.