Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Changed

- Fixed client generation for trailing-slash paths that return arrays of inline objects. [#7876](https://github.com/microsoft/kiota/issues/7876)
- C#, Java, Go, PHP, Dart, TypeScript, Python and Ruby client: default value initialization in model classes for DateTime/Date/Time/UUID properties did not compile [#7404](https://github.com/microsoft/kiota/issues/7404)
- All languages: default value initialization in model classes for numeric/boolean properties was missing [#7404](https://github.com/microsoft/kiota/issues/7404)
- Fixed a bug where required query parameters from one HTTP operation were leaking into the path-item-level URL template, making them appear required for sibling operations on the same path. [#7292](https://github.com/microsoft/kiota/issues/7292)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,10 +93,10 @@ public static IEnumerable<IOpenApiParameter> GetPathParametersForCurrentSegment(
///<summary>
/// Returns the class name for the node with more or less precision depending on the provided arguments
///</summary>
internal static string GetClassName(this OpenApiUrlTreeNode currentNode, StructuredMimeTypesCollection structuredMimeTypes, string? suffix = default, string? prefix = default, OpenApiOperation? operation = default, IOpenApiResponse? response = default, IOpenApiSchema? schema = default, bool requestBody = false)
internal static string GetClassName(this OpenApiUrlTreeNode currentNode, StructuredMimeTypesCollection structuredMimeTypes, string? suffix = default, string? prefix = default, OpenApiOperation? operation = default, IOpenApiResponse? response = default, IOpenApiSchema? schema = default, bool requestBody = false, string? placeholder = null)
{
ArgumentNullException.ThrowIfNull(currentNode);
return currentNode.GetSegmentName(structuredMimeTypes, suffix, prefix, operation, response, schema, requestBody, static x => x.LastOrDefault() ?? string.Empty);
return currentNode.GetSegmentName(structuredMimeTypes, suffix, prefix, operation, response, schema, requestBody, static x => x.LastOrDefault() ?? string.Empty, placeholder: placeholder);
}
internal static string GetNavigationPropertyName(this OpenApiUrlTreeNode currentNode, StructuredMimeTypesCollection structuredMimeTypes, string? suffix = default, string? prefix = default, OpenApiOperation? operation = default, OpenApiResponse? response = default, OpenApiSchema? schema = default, bool requestBody = false, string? placeholder = null)
{
Expand Down
6 changes: 3 additions & 3 deletions src/Kiota.Builder/KiotaBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1766,7 +1766,7 @@ private CodeType CreateModelDeclarationAndType(OpenApiUrlTreeNode currentNode, I
_dynamicScope.Value!.Push(schema);
try
{
var className = string.IsNullOrEmpty(typeNameForInlineSchema) ? currentNode.GetClassName(config.StructuredMimeTypes, operation: operation, suffix: classNameSuffix, response: response, schema: schema, requestBody: isRequestBody).CleanupSymbolName() : typeNameForInlineSchema;
var className = string.IsNullOrEmpty(typeNameForInlineSchema) ? currentNode.GetClassName(config.StructuredMimeTypes, operation: operation, suffix: classNameSuffix, response: response, schema: schema, requestBody: isRequestBody, placeholder: TrailingSlashPlaceholder).CleanupSymbolName() : typeNameForInlineSchema;
var codeDeclaration = AddModelDeclarationIfDoesntExist(currentNode, operation, schema, className, codeNamespace);
return new CodeType { TypeDefinition = codeDeclaration };
}
Expand Down Expand Up @@ -1807,7 +1807,7 @@ private CodeClass CreateInheritedModelDeclarationCore(OpenApiUrlTreeNode current
cName :
(!string.IsNullOrEmpty(typeNameForInlineSchema) ?
typeNameForInlineSchema :
currentNode.GetClassName(config.StructuredMimeTypes, operation: operation, suffix: classNameSuffix, schema: schema, requestBody: isRequestBody)))
currentNode.GetClassName(config.StructuredMimeTypes, operation: operation, suffix: classNameSuffix, schema: schema, requestBody: isRequestBody, placeholder: TrailingSlashPlaceholder)))
.CleanupSymbolName();
var codeDeclaration = (rootSchemaHasProperties, inlineSchemas, referencedSchemas, isViaDiscriminator) switch
{
Expand Down Expand Up @@ -1867,7 +1867,7 @@ private CodeClass CreateInheritedModelDeclarationCore(OpenApiUrlTreeNode current
}
private CodeTypeBase CreateComposedModelDeclaration(OpenApiUrlTreeNode currentNode, IOpenApiSchema schema, OpenApiOperation? operation, string suffixForInlineSchema, CodeNamespace codeNamespace, bool isRequestBody, string typeNameForInlineSchema)
{
var typeName = string.IsNullOrEmpty(typeNameForInlineSchema) ? currentNode.GetClassName(config.StructuredMimeTypes, operation: operation, suffix: suffixForInlineSchema, schema: schema, requestBody: isRequestBody).CleanupSymbolName() : typeNameForInlineSchema;
var typeName = string.IsNullOrEmpty(typeNameForInlineSchema) ? currentNode.GetClassName(config.StructuredMimeTypes, operation: operation, suffix: suffixForInlineSchema, schema: schema, requestBody: isRequestBody, placeholder: TrailingSlashPlaceholder).CleanupSymbolName() : typeNameForInlineSchema;
var typesCount = schema.AnyOf?.Count ?? schema.OneOf?.Count ?? 0;
if ((typesCount == 1 && (schema.Type & JsonSchemaType.Null) is JsonSchemaType.Null && schema.IsInclusiveUnion() || // nullable on the root schema outside of anyOf
typesCount == 2 && (schema.AnyOf?.Any(static x => // nullable on a schema in the anyOf
Expand Down
49 changes: 49 additions & 0 deletions tests/Kiota.Builder.Tests/KiotaBuilderTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5057,6 +5057,55 @@ public void IncludesQueryParameterInUriTemplate()
Assert.Equal("\"{+baseurl}/api/contracts/{?type*}\"", emptyProperty.DefaultValue);
}
[Fact]
public void GeneratesInlineObjectArrayResponseForTrailingSlashPath()
{
var documentJSON =
"""
{
"openapi": "3.0.2",
"info": {
"title": "Sample API",
"version": "1.0"
},
"paths": {
"/test/": {
"get": {
"responses": {
"200": {
"description": "OK",
"content": {
"application/json": {
"schema": {
"type": "array",
"items": {
"type": "object"
}
}
}
}
}
}
}
}
}
}
""";
var (document, _) = OpenApiDocument.Parse(documentJSON, OpenApiConstants.Json);
var mockLogger = new Mock<ILogger<KiotaBuilder>>();
var builder = new KiotaBuilder(mockLogger.Object, new GenerationConfiguration { ClientClassName = "TestClient", ApiRootUrl = "https://localhost" }, _httpClient);
var node = builder.CreateUriSpace(document);

var codeModel = builder.CreateSourceModel(node);

var requestBuilder = codeModel.FindChildByName<CodeClass>("EmptyPathSegmentRequestBuilder");
Assert.NotNull(requestBuilder);
var executor = requestBuilder.Methods.Single(static x => x.Kind is CodeMethodKind.RequestExecutor);
var returnType = Assert.IsType<CodeType>(executor.ReturnType);
Assert.Equal(CodeTypeBase.CodeTypeCollectionKind.Complex, returnType.CollectionKind);
var responseModel = Assert.IsType<CodeClass>(returnType.TypeDefinition);
Assert.Equal(KiotaBuilder.TrailingSlashPlaceholder, responseModel.Name);
}
[Fact]
public void MapsArrayOfTypesAsUnionType()
{
var document = new OpenApiDocument
Expand Down