Skip to content

Commit

Permalink
Merge pull request #1421 from lnash94/internal_361_1.6.x
Browse files Browse the repository at this point in the history
[1.6.x] Add fix for handling `additionalProperties` field in requestBody in service generation
  • Loading branch information
lnash94 authored Jun 28, 2023
2 parents d44d8dd + 15df764 commit 6db22d6
Show file tree
Hide file tree
Showing 10 changed files with 217 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -222,4 +222,23 @@ public void testForAnyOf() throws IOException, BallerinaOpenApiException {
CommonTestFunctions.compareGeneratedSyntaxTreewithExpectedSyntaxTree(
"requestBody/any_of.bal", syntaxTree);
}

@Test(description = "RequestBody has object type with additional property")
public void testForAdditionalProperty() throws IOException, BallerinaOpenApiException {
Path definitionPath = RES_DIR.resolve("swagger/requestBody/additional_property.yaml");
OpenAPI openAPI = GeneratorUtils.normalizeOpenAPI(definitionPath, false);
OASServiceMetadata oasServiceMetadata = new OASServiceMetadata.Builder()
.withOpenAPI(openAPI)
.withFilters(filter)
.build();
BallerinaServiceGenerator ballerinaServiceGenerator = new BallerinaServiceGenerator(oasServiceMetadata);
syntaxTree = ballerinaServiceGenerator.generateSyntaxTree();
BallerinaTypesGenerator ballerinaTypesGenerator = new BallerinaTypesGenerator(openAPI, false,
ballerinaServiceGenerator.getTypeInclusionRecords());
SyntaxTree typeSyntaxTree = ballerinaTypesGenerator.generateSyntaxTree();
CommonTestFunctions.compareGeneratedSyntaxTreewithExpectedSyntaxTree(
"requestBody/additional_property.bal", syntaxTree);
CommonTestFunctions.compareGeneratedSyntaxTreewithExpectedSyntaxTree(
"requestBody/additional_prop_types.bal", typeSyntaxTree);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,14 @@ service /api/v3 on ep0 {
# http:BadRequest (Invalid ID supplied)
# http:NotFound (Pet not found)
# http:MethodNotAllowed (Validation exception)
resource function put pet(@http:Payload Pet|xml|map<string> payload) returns Pet|xml|http:BadRequest|http:NotFound|http:MethodNotAllowed {
resource function put pet(@http:Payload xml|map<string>|Pet payload) returns Pet|xml|http:BadRequest|http:NotFound|http:MethodNotAllowed {
}
# Add a new pet to the store
#
# + payload - Create a new pet in the store
# + return - returns can be any of following types
# OkPetXml (Successful operation)
# http:MethodNotAllowed (Invalid input)
resource function post pet(@http:Payload Pet|xml|map<string> payload) returns OkPetXml|http:MethodNotAllowed {
resource function post pet(@http:Payload xml|map<string>|Pet payload) returns OkPetXml|http:MethodNotAllowed {
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,13 @@ service /v2 on ep0 {
# http:BadRequest (Invalid ID supplied)
# http:NotFound (Pet not found)
# http:MethodNotAllowed (Validation exception)
resource function put pet(@http:Payload Pet|xml payload) returns http:BadRequest|http:NotFound|http:MethodNotAllowed {
resource function put pet(@http:Payload xml|Pet payload) returns http:BadRequest|http:NotFound|http:MethodNotAllowed {
}
# Add a new pet to the store
#
# + payload - Pet object that needs to be added to the store
# + return - Invalid input
resource function post pet(@http:Payload Pet|xml payload) returns http:MethodNotAllowed {
resource function post pet(@http:Payload xml|Pet payload) returns http:MethodNotAllowed {
}
# Finds Pets by status
#
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
public type Mailing_AddContact_body record {
string name?;
};

public type Mailing_AddContact_body_1 record {
string name?;
};

public type Mailing_AddContact_body_2 record {|
string name?;
int...;
|};

public type MailingViewModel record {|
string? name?;
string? email?;
boolean optPhoneNumber?;
string? phoneNumber?;
string? motivoRecusa?;
|};

public type Mailing_AddContact_body_3 record {|
string name?;
MailingViewModel...;
|};

public type HistoricoSimulacaoViewModel record {|
string? email?;
string? data?;
string? step?;
string? descricao?;
|};
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import ballerina/http;

listener http:Listener ep0 = new (9090, config = {host: "localhost"});

service / on ep0 {
# Description
#
# + payload - parameter description
# + return - Success
resource function post api/HistoricoSimulacao/AddHistorico(@http:Payload record {|string...;|}|record {|HistoricoSimulacaoViewModel...;|}|record {|record {|string...;|}...;|} payload) returns http:Ok {
}
# Description
#
# + payload - parameter description
# + return - Success
resource function put api/Mailing/AddContact(@http:Payload Mailing_AddContact_body|Mailing_AddContact_body_1 payload) returns http:Ok {
}
# Description
#
# + payload - parameter description
# + return - Success
resource function post api/Mailing/AddContact(@http:Payload Mailing_AddContact_body_2|Mailing_AddContact_body_3 payload) returns http:Ok {
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,6 @@ service /v1 on ep0 {
#
# + payload - Optional description in *Markdown*
# + return - OK
resource function post pets(@http:Payload Pet|xml|map<string>|string payload) returns http:Ok {
resource function post pets(@http:Payload string|xml|map<string>|Pet payload) returns http:Ok {
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,12 @@ service /v1 on ep0 {
#
# + payload - Optional description in *Markdown*
# + return - OK
resource function post pets(@http:Payload Pet|xml|map<string>|string payload) returns http:Ok {
resource function post pets(@http:Payload string|xml|map<string>|Pet payload) returns http:Ok {
}
# List all pets
#
# + payload - parameter description
# + return - OK
resource function post pets02(@http:Payload Pet|xml payload) returns http:Created {
resource function post pets02(@http:Payload xml|Pet payload) returns http:Created {
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
openapi: 3.0.1
info:
title: APITest
contact:
name: Samuel Apolion Benevenuto
version: v1
paths:
/api/HistoricoSimulacao/AddHistorico:
post:
tags:
- HistoricoSimulacao
requestBody:
content:
application/json-patch+json:
schema:
type: object
additionalProperties: #addtionalProperties with primitive types
type: string
application/json:
schema:
type: object
additionalProperties: #addtionalProperties with reference
$ref: '#/components/schemas/HistoricoSimulacaoViewModel'
application/path+json:
schema:
type: object
additionalProperties: #addtionalProperties with reference
type: object
additionalProperties:
type: string
responses:
'200':
description: Success
x-auth-type: None
x-throttling-tier: Unlimited
/api/Mailing/AddContact:
post:
tags:
- Mailing
requestBody:
content:
application/json-patch+json:
schema:
type: object
properties:
name:
type: string
additionalProperties: #Object schema with properties and additionalProperties fields
type: integer
application/json:
schema:
type: object
properties:
name:
type: string
additionalProperties: #Object schema with properties and additionalProperties with reference fields
$ref: '#/components/schemas/MailingViewModel'
responses:
'200':
description: Success
x-auth-type: None
x-throttling-tier: Unlimited
put:
tags:
- Mailing
requestBody:
content:
application/json-patch+json:
schema:
type: object
properties:
name:
type: string
additionalProperties: #Object schema with properties and additionalProperties fields
allOf:
- type: integer
application/json:
schema:
type: object
properties:
name:
type: string
additionalProperties: #Object schema with properties and additionalProperties with reference fields
oneOf:
- type: integer
- $ref: '#/components/schemas/MailingViewModel'
responses:
'200':
description: Success
x-auth-type: None
x-throttling-tier: Unlimited
components:
schemas:
HistoricoSimulacaoViewModel:
type: object
properties:
email:
type: string
nullable: true
data:
type: string
format: date-time
nullable: true
step:
type: string
nullable: true
descricao:
type: string
nullable: true
additionalProperties: false
MailingViewModel:
type: object
properties:
name:
type: string
nullable: true
email:
type: string
nullable: true
optPhoneNumber:
type: boolean
phoneNumber:
type: string
nullable: true
motivoRecusa:
type: string
nullable: true
additionalProperties: false
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,7 @@
import io.swagger.v3.oas.models.parameters.RequestBody;
import org.apache.commons.lang3.tuple.ImmutablePair;

import java.util.ArrayList;
import java.util.List;
import java.util.HashSet;
import java.util.Map;
import java.util.Optional;

Expand Down Expand Up @@ -77,7 +76,7 @@ public RequiredParameterNode createNodeForRequestBody() throws BallerinaOpenApiE
// public type PayloadType string|json|xml|byte[]|CustomRecord|CustomRecord[] ;
Optional<TypeDescriptorNode> typeName;
// Filter same data type
List<String> types = new ArrayList<>();
HashSet<String> types = new HashSet<>();
for (Map.Entry<String, MediaType> mime : requestBody.getContent().entrySet()) {
typeName = getNodeForPayloadType(mime);
if (typeName.isPresent()) {
Expand All @@ -92,7 +91,7 @@ public RequiredParameterNode createNodeForRequestBody() throws BallerinaOpenApiE
String result = String.join(PIPE, types);
typeName = Optional.of(NodeParser.parseTypeDescriptor(result));
} else {
typeName = Optional.of(NodeParser.parseTypeDescriptor(types.get(0)));
typeName = Optional.of(NodeParser.parseTypeDescriptor(types.iterator().next()));
}
AnnotationNode annotationNode = getAnnotationNode(GeneratorConstants.PAYLOAD_KEYWORD, null);
NodeList<AnnotationNode> annotation = NodeFactory.createNodeList(annotationNode);
Expand Down Expand Up @@ -163,5 +162,4 @@ null, createIdentifierToken(GeneratorConstants.BYTE)),
}
return typeName;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,9 @@ public static ImmutablePair<Optional<TypeDescriptorNode>, Optional<TypeDefinitio
JSON))), Optional.empty());
} else if (returnTypeDecNode.get() instanceof RecordTypeDescriptorNode) {
RecordTypeDescriptorNode recordNode = (RecordTypeDescriptorNode) returnTypeDecNode.get();
if (recordName == null) {
return ImmutablePair.of(returnTypeDecNode, Optional.empty());
}
TypeDefinitionNode typeDefinitionNode = createTypeDefinitionNode(null,
createToken(PUBLIC_KEYWORD),
createToken(TYPE_KEYWORD),
Expand Down

0 comments on commit 6db22d6

Please sign in to comment.