diff --git a/openapi-bal-service/src/main/java/io/ballerina/openapi/converter/Constants.java b/openapi-bal-service/src/main/java/io/ballerina/openapi/converter/Constants.java index d1a2a97c7..aeb3e1bdf 100644 --- a/openapi-bal-service/src/main/java/io/ballerina/openapi/converter/Constants.java +++ b/openapi-bal-service/src/main/java/io/ballerina/openapi/converter/Constants.java @@ -82,6 +82,8 @@ public class Constants { public static final String WILD_CARD_SUMMARY = "Any type of entity body"; public static final String MEDIA_TYPE = "mediaType"; public static final String TUPLE = "tuple"; + public static final String REGEX_INTERPOLATION_PATTERN = "^(?!.*\\$\\{).+$"; + public static final String DATE_CONSTRAINT_ANNOTATION = "constraint:Date"; /** * Enum to select the Ballerina Type. diff --git a/openapi-bal-service/src/main/java/io/ballerina/openapi/converter/diagnostic/DiagnosticMessages.java b/openapi-bal-service/src/main/java/io/ballerina/openapi/converter/diagnostic/DiagnosticMessages.java index 4bb67ca96..159c5286b 100644 --- a/openapi-bal-service/src/main/java/io/ballerina/openapi/converter/diagnostic/DiagnosticMessages.java +++ b/openapi-bal-service/src/main/java/io/ballerina/openapi/converter/diagnostic/DiagnosticMessages.java @@ -61,12 +61,19 @@ public enum DiagnosticMessages { DiagnosticSeverity.WARNING), OAS_CONVERTOR_114("OAS_CONVERTOR_114", "Generated OpenAPI definition does not contain information " + "for Ballerina type '%s'. ", DiagnosticSeverity.WARNING), - OAS_CONVERTOR_115("OAS_CONVERTOR_115", "Given Ballerina file does not contain any HTTP service.", DiagnosticSeverity.ERROR), - OAS_CONVERTOR_116("OAS_CONVERTOR_116", "Generated OpenAPI definition does not contain `%s` request" + + OAS_CONVERTOR_116("OAS_CONVERTOR_116", "Failed to parse the Number value due to: %s ", + DiagnosticSeverity.ERROR), + OAS_CONVERTOR_117("OAS_CONVERTOR_117", "Generated OpenAPI definition does not contain `%s` request" + " body information, as it's not supported by the OpenAPI tool.", - DiagnosticSeverity.WARNING); + DiagnosticSeverity.WARNING), + OAS_CONVERTOR_118("OAS_CONVERTOR_118", "Generated OpenAPI definition does not contain variable " + + "assignment '%s' in constraint validation.", DiagnosticSeverity.WARNING), + OAS_CONVERTOR_119("OAS_CONVERTOR_119", "Given REGEX pattern '%s' is not supported by the OpenAPI " + + "tool, it may also not support interpolation within the REGEX pattern.", DiagnosticSeverity.WARNING), + OAS_CONVERTOR_120("OAS_CONVERTER_120", "Ballerina Date constraints might not be reflected in the " + + "OpenAPI definition", DiagnosticSeverity.WARNING); private final String code; private final String description; diff --git a/openapi-bal-service/src/main/java/io/ballerina/openapi/converter/service/ConstraintAnnotation.java b/openapi-bal-service/src/main/java/io/ballerina/openapi/converter/service/ConstraintAnnotation.java new file mode 100644 index 000000000..ed562cf9a --- /dev/null +++ b/openapi-bal-service/src/main/java/io/ballerina/openapi/converter/service/ConstraintAnnotation.java @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package io.ballerina.openapi.converter.service; + +import java.util.Optional; + +/** + * This @link ConstraintAnnotation} class represents the constraint annotations. + * + * @since 1.9.0 + */ +public class ConstraintAnnotation { + private final String minValue; + private final String maxValue; + private final String length; + private final String minLength; + private final String maxLength; + private final String minValueExclusive; + private final String maxValueExclusive; + private final String pattern; + + public ConstraintAnnotation(ConstraintAnnotationBuilder builder) { + this.minValue = builder.minValue; + this.maxValue = builder.maxValue; + this.length = builder.length; + this.minLength = builder.minLength; + this.maxLength = builder.maxLength; + this.minValueExclusive = builder.minValueExclusive; + this.maxValueExclusive = builder.maxValueExclusive; + this.pattern = builder.pattern; + } + + public Optional getMinValue() { + return Optional.ofNullable(minValue); + } + + public Optional getMaxValue() { + return Optional.ofNullable(maxValue); + } + + public Optional getLength() { + return Optional.ofNullable(length); + } + + public Optional getMinLength() { + return Optional.ofNullable(minLength); + } + + public Optional getMaxLength() { + return Optional.ofNullable(maxLength); + } + + public Optional getMinValueExclusive() { + return Optional.ofNullable(minValueExclusive); + } + + public Optional getMaxValueExclusive() { + return Optional.ofNullable(maxValueExclusive); + } + + public Optional getPattern() { + return Optional.ofNullable(pattern); + } + + /** + * This is the builder class for the {@link ConstraintAnnotation}. + */ + public static class ConstraintAnnotationBuilder { + private String minValue; + private String maxValue; + private String length; + private String minLength; + private String maxLength; + private String minValueExclusive; + private String maxValueExclusive; + private String pattern; + + public ConstraintAnnotationBuilder withMinValue(String minValue) { + this.minValue = minValue; + return this; + } + + public ConstraintAnnotationBuilder withLength(String length) { + this.length = length; + return this; + } + + public ConstraintAnnotationBuilder withMaxValue(String maxValue) { + this.maxValue = maxValue; + return this; + } + + public ConstraintAnnotationBuilder withMinLength(String minLength) { + this.minLength = minLength; + return this; + } + + public ConstraintAnnotationBuilder withMaxLength(String maxLength) { + this.maxLength = maxLength; + return this; + } + + public ConstraintAnnotationBuilder withMinValueExclusive(String minValueExclusive) { + this.minValueExclusive = minValueExclusive; + return this; + } + + public ConstraintAnnotationBuilder withMaxValueExclusive(String maxValueExclusive) { + this.maxValueExclusive = maxValueExclusive; + return this; + } + + public ConstraintAnnotationBuilder withPattern(String pattern) { + this.pattern = pattern; + return this; + } + + public ConstraintAnnotation build() { + ConstraintAnnotation constraintAnnotation = new ConstraintAnnotation(this); + return constraintAnnotation; + } + } +} diff --git a/openapi-bal-service/src/main/java/io/ballerina/openapi/converter/service/ModuleMemberVisitor.java b/openapi-bal-service/src/main/java/io/ballerina/openapi/converter/service/ModuleMemberVisitor.java index 252325a26..c9182039f 100644 --- a/openapi-bal-service/src/main/java/io/ballerina/openapi/converter/service/ModuleMemberVisitor.java +++ b/openapi-bal-service/src/main/java/io/ballerina/openapi/converter/service/ModuleMemberVisitor.java @@ -22,8 +22,8 @@ import io.ballerina.compiler.syntax.tree.NodeVisitor; import io.ballerina.compiler.syntax.tree.TypeDefinitionNode; -import java.util.LinkedList; -import java.util.List; +import java.util.LinkedHashSet; +import java.util.Set; /** * Visitor to get the TypeDefinitionNode and ListenerDeclarationNodes. @@ -32,8 +32,8 @@ */ public class ModuleMemberVisitor extends NodeVisitor { - LinkedList typeDefinitionNodes = new LinkedList<>(); - LinkedList listenerDeclarationNodes = new LinkedList<>(); + Set typeDefinitionNodes = new LinkedHashSet<>(); + Set listenerDeclarationNodes = new LinkedHashSet<>(); @Override public void visit(TypeDefinitionNode typeDefinitionNode) { @@ -45,11 +45,11 @@ public void visit(ListenerDeclarationNode listenerDeclarationNode) { listenerDeclarationNodes.add(listenerDeclarationNode); } - public List getTypeDefinitionNodes() { + public Set getTypeDefinitionNodes() { return typeDefinitionNodes; } - public List getListenerDeclarationNodes() { + public Set getListenerDeclarationNodes() { return listenerDeclarationNodes; } } diff --git a/openapi-bal-service/src/main/java/io/ballerina/openapi/converter/service/OpenAPIComponentMapper.java b/openapi-bal-service/src/main/java/io/ballerina/openapi/converter/service/OpenAPIComponentMapper.java index 9eee7fa1d..a0e075dbf 100644 --- a/openapi-bal-service/src/main/java/io/ballerina/openapi/converter/service/OpenAPIComponentMapper.java +++ b/openapi-bal-service/src/main/java/io/ballerina/openapi/converter/service/OpenAPIComponentMapper.java @@ -36,7 +36,22 @@ import io.ballerina.compiler.api.symbols.TypeReferenceTypeSymbol; import io.ballerina.compiler.api.symbols.TypeSymbol; import io.ballerina.compiler.api.symbols.UnionTypeSymbol; +import io.ballerina.compiler.syntax.tree.AnnotationNode; +import io.ballerina.compiler.syntax.tree.ExpressionNode; +import io.ballerina.compiler.syntax.tree.IntersectionTypeDescriptorNode; +import io.ballerina.compiler.syntax.tree.MappingConstructorExpressionNode; +import io.ballerina.compiler.syntax.tree.MetadataNode; +import io.ballerina.compiler.syntax.tree.Node; +import io.ballerina.compiler.syntax.tree.NodeList; +import io.ballerina.compiler.syntax.tree.QualifiedNameReferenceNode; +import io.ballerina.compiler.syntax.tree.RecordFieldNode; +import io.ballerina.compiler.syntax.tree.RecordTypeDescriptorNode; +import io.ballerina.compiler.syntax.tree.SpecificFieldNode; +import io.ballerina.compiler.syntax.tree.SyntaxKind; +import io.ballerina.compiler.syntax.tree.TemplateExpressionNode; +import io.ballerina.compiler.syntax.tree.TypeDefinitionNode; import io.ballerina.openapi.converter.diagnostic.DiagnosticMessages; +import io.ballerina.openapi.converter.diagnostic.ExceptionDiagnostic; import io.ballerina.openapi.converter.diagnostic.IncompatibleResourceDiagnostic; import io.ballerina.openapi.converter.diagnostic.OpenAPIConverterDiagnostic; import io.ballerina.openapi.converter.utils.ConverterCommonUtils; @@ -49,6 +64,9 @@ import io.swagger.v3.oas.models.media.Schema; import io.swagger.v3.oas.models.media.StringSchema; +import java.math.BigDecimal; +import java.text.NumberFormat; +import java.text.ParseException; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; @@ -57,11 +75,14 @@ import java.util.Locale; import java.util.Map; import java.util.Optional; +import java.util.Set; import static io.ballerina.openapi.converter.Constants.DOUBLE; import static io.ballerina.openapi.converter.Constants.FLOAT; import static io.ballerina.openapi.converter.Constants.HTTP; import static io.ballerina.openapi.converter.Constants.HTTP_CODES; +import static io.ballerina.openapi.converter.Constants.REGEX_INTERPOLATION_PATTERN; +import static io.ballerina.openapi.converter.Constants.DATE_CONSTRAINT_ANNOTATION; /** * This util class for processing the mapping in between ballerina record and openAPI object schema. @@ -69,14 +90,15 @@ * @since 2.0.0 */ public class OpenAPIComponentMapper { - private final Components components; private final List diagnostics; private final HashSet visitedTypeDefinitionNames = new HashSet<>(); + private final Set typeDefinitionNodes; - public OpenAPIComponentMapper(Components components) { - this.components = components; - this.diagnostics = new ArrayList<>(); + public OpenAPIComponentMapper(Components components, ModuleMemberVisitor moduleMemberVisitor) { + this.components = components; + this.diagnostics = new ArrayList<>(); + this.typeDefinitionNodes = moduleMemberVisitor.getTypeDefinitionNodes(); } public List getDiagnostics() { @@ -102,11 +124,22 @@ public void createComponentSchema(Map schema, TypeSymbol typeSym } TypeReferenceTypeSymbol typeRef = (TypeReferenceTypeSymbol) typeSymbol; TypeSymbol type = typeRef.typeDescriptor(); - if (type.typeKind() == TypeDescKind.INTERSECTION) { type = excludeReadonlyIfPresent(type); } + //Access module part node for finding the node to given typeSymbol. + ConstraintAnnotation.ConstraintAnnotationBuilder constraintBuilder = + new ConstraintAnnotation.ConstraintAnnotationBuilder(); + ((TypeReferenceTypeSymbol) typeSymbol).definition().getName().ifPresent(name -> { + for (TypeDefinitionNode typeDefinitionNode : typeDefinitionNodes) { + if (typeDefinitionNode.typeName().text().equals(name) && typeDefinitionNode.metadata().isPresent()) { + extractedConstraintAnnotation(typeDefinitionNode.metadata().get(), constraintBuilder); + } + } + }); + ConstraintAnnotation constraintAnnot = constraintBuilder.build(); + switch (type.typeKind()) { case RECORD: // Handle typeInclusions with allOf type binding @@ -123,7 +156,9 @@ public void createComponentSchema(Map schema, TypeSymbol typeSym } break; case STRING: - schema.put(componentName, new StringSchema().description(typeDoc)); + Schema stringSchema = new StringSchema().description(typeDoc); + setConstraintValueToSchema(constraintAnnot, stringSchema); + schema.put(componentName, stringSchema); components.setSchemas(schema); break; case JSON: @@ -132,21 +167,28 @@ public void createComponentSchema(Map schema, TypeSymbol typeSym components.setSchemas(schema); break; case INT: - schema.put(componentName, new IntegerSchema().description(typeDoc)); + Schema intSchema = new IntegerSchema().description(typeDoc); + setConstraintValueToSchema(constraintAnnot, intSchema); + schema.put(componentName, intSchema); components.setSchemas(schema); break; case DECIMAL: - schema.put(componentName, new NumberSchema().format(DOUBLE).description(typeDoc)); + Schema decimalSchema = new NumberSchema().format(DOUBLE).description(typeDoc); + setConstraintValueToSchema(constraintAnnot, decimalSchema); + schema.put(componentName, decimalSchema); components.setSchemas(schema); break; case FLOAT: - schema.put(componentName, new NumberSchema().format(FLOAT).description(typeDoc)); + Schema floatSchema = new NumberSchema().format(FLOAT).description(typeDoc); + setConstraintValueToSchema(constraintAnnot, floatSchema); + schema.put(componentName, floatSchema); components.setSchemas(schema); break; case ARRAY: case TUPLE: ArraySchema arraySchema = mapArrayToArraySchema(schema, type, componentName); - schema.put(componentName, arraySchema.description(typeDoc)); + setConstraintValueToSchema(constraintAnnot, arraySchema.description(typeDoc)); + schema.put(componentName, arraySchema); components.setSchemas(schema); break; case UNION: @@ -326,7 +368,43 @@ private ObjectSchema generateObjectSchemaFromRecordFields(Map sc List required = new ArrayList<>(); componentSchema.setDescription(apiDocs.get(componentName)); Map schemaProperties = new LinkedHashMap<>(); + RecordTypeDescriptorNode recordNode = null; + // Get the recordNode type descriptor node from given recordNode type symbol + for (TypeDefinitionNode typeDefinitionNode : typeDefinitionNodes) { + if (typeDefinitionNode.typeName().text().equals(componentName)) { + if (typeDefinitionNode.typeDescriptor().kind().equals(SyntaxKind.RECORD_TYPE_DESC)) { + recordNode = (RecordTypeDescriptorNode) typeDefinitionNode.typeDescriptor(); + } else if (typeDefinitionNode.typeDescriptor().kind().equals(SyntaxKind.INTERSECTION_TYPE_DESC)) { + IntersectionTypeDescriptorNode intersecNode = + (IntersectionTypeDescriptorNode) typeDefinitionNode.typeDescriptor(); + Node leftTypeDesc = intersecNode.leftTypeDesc(); + Node rightTypeDesc = intersecNode.rightTypeDesc(); + if (leftTypeDesc.kind().equals(SyntaxKind.RECORD_TYPE_DESC)) { + recordNode = (RecordTypeDescriptorNode) leftTypeDesc; + } + if (rightTypeDesc.kind().equals(SyntaxKind.RECORD_TYPE_DESC)) { + recordNode = (RecordTypeDescriptorNode) rightTypeDesc; + } + } + } + } + for (Map.Entry field : rfields.entrySet()) { + ConstraintAnnotation.ConstraintAnnotationBuilder constraintBuilder = + new ConstraintAnnotation.ConstraintAnnotationBuilder(); + if (recordNode != null) { + for (Node node : recordNode.fields()) { + if (node instanceof RecordFieldNode) { + RecordFieldNode fieldNode = (RecordFieldNode) node; + if (fieldNode.fieldName().toString().equals(field.getKey())) { + Optional metadata = fieldNode.metadata(); + metadata.ifPresent(metadataNode -> extractedConstraintAnnotation(metadataNode, + constraintBuilder)); + } + } + } + } + ConstraintAnnotation constraintAnnot = constraintBuilder.build(); String fieldName = ConverterCommonUtils.unescapeIdentifier(field.getKey().trim()); if (!field.getValue().isOptional()) { required.add(fieldName); @@ -362,10 +440,12 @@ private ObjectSchema generateObjectSchemaFromRecordFields(Map sc property.setNullable(nullable); schema = components.getSchemas(); } - // Add API documentation for record field + // Add API documentation for recordNode field if (apiDocs.containsKey(fieldName)) { property.setDescription(apiDocs.get(fieldName)); } + // Assign value to property - string, number, array + setConstraintValueToSchema(constraintAnnot, property); schemaProperties.put(fieldName, property); } componentSchema.setProperties(schemaProperties); @@ -406,7 +486,7 @@ private Schema handleMapType(Map schema, String componentName, S } /** - * This function uses to handle the field datatype has TypeReference(ex: Record or Enum). + * This function is used to handle the field datatype has TypeReference(ex: Record or Enum). */ private Schema handleTypeReference(Map schema, TypeReferenceTypeSymbol typeReferenceSymbol, Schema property, boolean isCyclicRecord) { @@ -424,7 +504,7 @@ private Schema handleTypeReference(Map schema, TypeReferenceT } /** - * This function uses to generate schema when field has union type as data type. + * This function is used to generate schema when field has union type as data type. *
      *     type Pet record {
      *         Dog|Cat type;
@@ -493,7 +573,7 @@ private boolean isSameRecord(String parentComponentName, TypeReferenceTypeSymbol
     }
 
     /**
-     * This function generate oneOf composed schema for record fields.
+     * This function generates oneOf composed schema for record fields.
      */
     private Schema generateOneOfSchema(Schema property, List properties) {
         boolean isTypeReference = properties.size() == 1 && properties.get(0).get$ref() == null;
@@ -610,7 +690,7 @@ private Schema getSchemaForUnionType(UnionTypeSymbol symbol, Schema symbolProper
     }
 
     /**
-     * This util function is to handle the type reference symbol is record type or enum type.
+     * This util function is used to handle the type reference symbol is record type or enum type.
      */
     private Schema getSchemaForTypeReferenceSymbol(TypeSymbol referenceType, Schema symbolProperty,
                                                    String componentName, Map schema) {
@@ -642,4 +722,237 @@ private ArraySchema handleArray(int arrayDimensions, Schema property, ArraySchem
         }
         return arrayProperty;
     }
+
+    /**
+     * This util is used to set the integer constraint values for relevant schema field.
+     */
+    private void setIntegerConstraintValuesToSchema(ConstraintAnnotation constraintAnnot, IntegerSchema properties) {
+        BigDecimal minimum = null;
+        BigDecimal maximum = null;
+        if (constraintAnnot.getMinValue().isPresent()) {
+            minimum = BigDecimal.valueOf(Integer.parseInt(constraintAnnot.getMinValue().get()));
+        } else if (constraintAnnot.getMinValueExclusive().isPresent()) {
+            minimum = BigDecimal.valueOf(Integer.parseInt(constraintAnnot.getMinValueExclusive().get()));
+            properties.setExclusiveMinimum(true);
+        }
+
+        if (constraintAnnot.getMaxValue().isPresent()) {
+            maximum = BigDecimal.valueOf(Integer.parseInt(constraintAnnot.getMaxValue().get()));
+        } else if (constraintAnnot.getMaxValueExclusive().isPresent()) {
+            maximum = BigDecimal.valueOf(Integer.parseInt(constraintAnnot.getMaxValueExclusive().get()));
+            properties.setExclusiveMaximum(true);
+        }
+        properties.setMinimum(minimum);
+        properties.setMaximum(maximum);
+    }
+
+    /**
+     * This util is used to set the number (float, double) constraint values for relevant schema field.
+     */
+    private void setNumberConstraintValuesToSchema(ConstraintAnnotation constraintAnnot, NumberSchema properties)
+                                                        throws ParseException {
+        BigDecimal minimum = null;
+        BigDecimal maximum = null;
+        if (constraintAnnot.getMinValue().isPresent()) {
+            minimum = BigDecimal.valueOf((NumberFormat.getInstance()
+                    .parse(constraintAnnot.getMinValue().get()).doubleValue()));
+        } else if (constraintAnnot.getMinValueExclusive().isPresent()) {
+            minimum = BigDecimal.valueOf((NumberFormat.getInstance()
+                    .parse(constraintAnnot.getMinValueExclusive().get()).doubleValue()));
+            properties.setExclusiveMinimum(true);
+        }
+
+        if (constraintAnnot.getMaxValue().isPresent()) {
+            maximum = BigDecimal.valueOf((NumberFormat.getInstance()
+                    .parse(constraintAnnot.getMaxValue().get()).doubleValue()));
+        } else if (constraintAnnot.getMaxValueExclusive().isPresent()) {
+            maximum = BigDecimal.valueOf((NumberFormat.getInstance()
+                    .parse(constraintAnnot.getMaxValueExclusive().get()).doubleValue()));
+            properties.setExclusiveMaximum(true);
+        }
+        properties.setMinimum(minimum);
+        properties.setMaximum(maximum);
+    }
+
+    /**
+     * This util is used to set the string constraint values for relevant schema field.
+     */
+    private void setStringConstraintValuesToSchema(ConstraintAnnotation constraintAnnot, StringSchema properties) {
+        if (constraintAnnot.getLength().isPresent()) {
+            properties.setMinLength(Integer.valueOf(constraintAnnot.getLength().get()));
+            properties.setMaxLength(Integer.valueOf(constraintAnnot.getLength().get()));
+        } else {
+            properties.setMaxLength(constraintAnnot.getMaxLength().isPresent() ?
+                    Integer.valueOf(constraintAnnot.getMaxLength().get()) : null);
+            properties.setMinLength(constraintAnnot.getMinLength().isPresent() ?
+                    Integer.valueOf(constraintAnnot.getMinLength().get()) : null);
+        }
+
+        if (constraintAnnot.getPattern().isPresent()) {
+            String regexPattern = constraintAnnot.getPattern().get();
+            properties.setPattern(regexPattern);
+        }
+    }
+
+    /**
+     * This util is used to set the array constraint values for relevant schema field.
+     */
+    private void setArrayConstraintValuesToSchema(ConstraintAnnotation constraintAnnot, ArraySchema properties) {
+        if (constraintAnnot.getLength().isPresent()) {
+            properties.setMinItems(Integer.valueOf(constraintAnnot.getLength().get()));
+            properties.setMaxItems(Integer.valueOf(constraintAnnot.getLength().get()));
+        } else {
+            properties.setMaxItems(constraintAnnot.getMaxLength().isPresent() ?
+                    Integer.valueOf(constraintAnnot.getMaxLength().get()) : null);
+            properties.setMinItems(constraintAnnot.getMinLength().isPresent() ?
+                    Integer.valueOf(constraintAnnot.getMinLength().get()) : null);
+        }
+    }
+
+    /**
+     * This util is used to set the constraint values for relevant schema field.
+     */
+    private void setConstraintValueToSchema(ConstraintAnnotation constraintAnnot, Schema properties) {
+        try {
+            //Ballerina currently supports only Int, Number (Float, Decimal), String & Array constraints,
+            //with plans to extend constraint support in the future.
+            if (properties instanceof ArraySchema arraySchema) {
+                setArrayConstraintValuesToSchema(constraintAnnot, arraySchema);
+            } else if (properties instanceof StringSchema stringSchema) {
+                setStringConstraintValuesToSchema(constraintAnnot, stringSchema);
+            } else if (properties instanceof IntegerSchema integerSchema) {
+                setIntegerConstraintValuesToSchema(constraintAnnot, integerSchema);
+            } else if (properties instanceof NumberSchema numberSchema) {
+                setNumberConstraintValuesToSchema(constraintAnnot, numberSchema);
+            }
+        } catch (ParseException parseException) {
+            DiagnosticMessages error = DiagnosticMessages.OAS_CONVERTOR_114;
+            ExceptionDiagnostic diagnostic = new ExceptionDiagnostic(error.getCode(),
+                    error.getDescription(), null, parseException.getMessage());
+            diagnostics.add(diagnostic);
+        }
+    }
+
+    /**
+     * This util is used to extract the annotation values in `@constraint` and store it in builder.
+     */
+    private void extractedConstraintAnnotation(MetadataNode metadata,
+                                               ConstraintAnnotation.ConstraintAnnotationBuilder constraintBuilder) {
+        NodeList annotations = metadata.annotations();
+        annotations.stream()
+                .filter(this::isConstraintAnnotation)
+                .filter(annotation -> annotation.annotValue().isPresent())
+                .forEach(annotation -> {
+                    if (isDateConstraint(annotation)) {
+                        DiagnosticMessages errorMsg = DiagnosticMessages.OAS_CONVERTOR_120;
+                        IncompatibleResourceDiagnostic error = new IncompatibleResourceDiagnostic(errorMsg,
+                                annotation.location(), annotation.toString());
+                        diagnostics.add(error);
+                        return;
+                    }
+                    MappingConstructorExpressionNode annotationValue = annotation.annotValue().get();
+                    annotationValue.fields().stream()
+                            .filter(field -> SyntaxKind.SPECIFIC_FIELD.equals(field.kind()))
+                            .forEach(field -> {
+                                String name = ((SpecificFieldNode) field).fieldName().toString().trim();
+                                processConstraintAnnotation((SpecificFieldNode) field, name, constraintBuilder);
+                            });
+                });
+    }
+
+    /**
+     * This util is used to check whether an annotation is a constraint annotation.
+     */
+    private boolean isConstraintAnnotation(AnnotationNode annotation) {
+        if (annotation.annotReference() instanceof QualifiedNameReferenceNode qualifiedNameRef) {
+            return qualifiedNameRef.modulePrefix().text().equals("constraint");
+        }
+        return false;
+    }
+
+    /*
+     * This util is used to check whether an annotation is a constraint:Date annotation.
+     * Currently, we don't have support for mapping Date constraints to OAS hence we skip them.
+     * {@link ...}
+     * Once the above improvement is completed this method should be removed!
+     */
+    private boolean isDateConstraint(AnnotationNode annotation) {
+        return annotation.annotReference().toString().trim().equals(DATE_CONSTRAINT_ANNOTATION);
+    }
+
+    /**
+     * This util is used to process the content of a constraint annotation.
+     */
+    private void processConstraintAnnotation(SpecificFieldNode specificFieldNode, String fieldName,
+                                             ConstraintAnnotation.ConstraintAnnotationBuilder constraintBuilder) {
+        specificFieldNode.valueExpr()
+                .flatMap(this::extractFieldValue)
+                .ifPresent(fieldValue -> fillConstraintValue(constraintBuilder, fieldName, fieldValue));
+    }
+
+    private Optional extractFieldValue(ExpressionNode exprNode) {
+        SyntaxKind syntaxKind = exprNode.kind();
+        switch (syntaxKind) {
+            case NUMERIC_LITERAL:
+                return Optional.of(exprNode.toString().trim());
+            case REGEX_TEMPLATE_EXPRESSION:
+                String regexContent = ((TemplateExpressionNode) exprNode).content().get(0).toString();
+                if (regexContent.matches(REGEX_INTERPOLATION_PATTERN)) {
+                    return Optional.of(regexContent);
+                } else {
+                    DiagnosticMessages errorMessage = DiagnosticMessages.OAS_CONVERTOR_119;
+                    IncompatibleResourceDiagnostic error = new IncompatibleResourceDiagnostic(errorMessage,
+                            exprNode.location(), regexContent);
+                    diagnostics.add(error);
+                    return Optional.empty();
+                }
+            case MAPPING_CONSTRUCTOR:
+                return ((MappingConstructorExpressionNode) exprNode).fields().stream()
+                    .filter(fieldNode -> ((SpecificFieldNode) fieldNode).fieldName().toString().trim().equals("value"))
+                    .findFirst()
+                    .flatMap(node -> ((SpecificFieldNode) node).valueExpr()
+                           .flatMap(this::extractFieldValue));
+            default:
+                DiagnosticMessages errorMessage = DiagnosticMessages.OAS_CONVERTOR_118;
+                IncompatibleResourceDiagnostic error = new IncompatibleResourceDiagnostic(errorMessage,
+                        exprNode.location(), exprNode.toString());
+                diagnostics.add(error);
+                return Optional.empty();
+        }
+    }
+
+    /**
+     * This util is used to build the constraint builder with available constraint annotation field value.
+     */
+    private void fillConstraintValue(ConstraintAnnotation.ConstraintAnnotationBuilder constraintBuilder,
+                                     String name, String constraintValue) {
+        switch (name) {
+            case "minValue":
+                constraintBuilder.withMinValue(constraintValue);
+                break;
+            case "maxValue":
+                constraintBuilder.withMaxValue(constraintValue);
+                break;
+            case "minValueExclusive":
+                constraintBuilder.withMinValueExclusive(constraintValue);
+                break;
+            case "maxValueExclusive":
+                constraintBuilder.withMaxValueExclusive(constraintValue);
+                break;
+            case "length":
+                constraintBuilder.withLength(constraintValue);
+                break;
+            case "maxLength":
+                constraintBuilder.withMaxLength(constraintValue);
+                break;
+            case "minLength":
+                constraintBuilder.withMinLength(constraintValue);
+                break;
+            case "pattern":
+                constraintBuilder.withPattern(constraintValue);
+                break;
+            default:
+                break;
+        }
+    }
 }
diff --git a/openapi-bal-service/src/main/java/io/ballerina/openapi/converter/service/OpenAPIEndpointMapper.java b/openapi-bal-service/src/main/java/io/ballerina/openapi/converter/service/OpenAPIEndpointMapper.java
index fa18fd196..e7a45e3e3 100644
--- a/openapi-bal-service/src/main/java/io/ballerina/openapi/converter/service/OpenAPIEndpointMapper.java
+++ b/openapi-bal-service/src/main/java/io/ballerina/openapi/converter/service/OpenAPIEndpointMapper.java
@@ -45,9 +45,9 @@
 
 import java.util.ArrayList;
 import java.util.Collections;
-import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Optional;
+import java.util.Set;
 
 import static io.ballerina.openapi.converter.Constants.PORT;
 import static io.ballerina.openapi.converter.Constants.SERVER;
@@ -66,7 +66,7 @@ public class OpenAPIEndpointMapper {
      * @param service   service node with bound endpoints
      * @return openapi definition with Server information
      */
-    public OpenAPI getServers(OpenAPI openAPI, LinkedHashSet endpoints,
+    public OpenAPI getServers(OpenAPI openAPI, Set endpoints,
                               ServiceDeclarationNode service) {
         openAPI = extractServerForExpressionNode(openAPI, service.expressions(), service);
         List servers = openAPI.getServers();
diff --git a/openapi-bal-service/src/main/java/io/ballerina/openapi/converter/service/OpenAPIHeaderMapper.java b/openapi-bal-service/src/main/java/io/ballerina/openapi/converter/service/OpenAPIHeaderMapper.java
index 70466d441..054859d71 100644
--- a/openapi-bal-service/src/main/java/io/ballerina/openapi/converter/service/OpenAPIHeaderMapper.java
+++ b/openapi-bal-service/src/main/java/io/ballerina/openapi/converter/service/OpenAPIHeaderMapper.java
@@ -59,11 +59,14 @@ public class OpenAPIHeaderMapper {
     private final Components components;
     private final SemanticModel semanticModel;
     private final Map apidocs;
+    private final ModuleMemberVisitor moduleMemberVisitor;
 
-    public OpenAPIHeaderMapper(Components components, SemanticModel semanticModel, Map apidocs) {
+    public OpenAPIHeaderMapper(Components components, SemanticModel semanticModel, Map apidocs,
+                               ModuleMemberVisitor moduleMemberVisitor) {
         this.apidocs = apidocs;
         this.components = components;
         this.semanticModel = semanticModel;
+        this.moduleMemberVisitor = moduleMemberVisitor;
     }
 
     /**
@@ -86,7 +89,7 @@ public List setHeaderParameter(RequiredParameterNode headerParam) {
 
         if (headerDetailNode.kind() == SyntaxKind.SIMPLE_NAME_REFERENCE) {
             SimpleNameReferenceNode refNode = (SimpleNameReferenceNode) headerDetailNode;
-            headerTypeSchema = handleReference(semanticModel, components, refNode);
+            headerTypeSchema = handleReference(semanticModel, components, refNode, moduleMemberVisitor);
         } else {
             headerTypeSchema = ConverterCommonUtils.getOpenApiSchema(getHeaderType(headerParam));
         }
@@ -126,7 +129,7 @@ public List setHeaderParameter(DefaultableParameterNode headerParam)
         Schema headerTypeSchema;
         if (headerParam.typeName().kind() == SyntaxKind.SIMPLE_NAME_REFERENCE) {
             SimpleNameReferenceNode refNode = (SimpleNameReferenceNode) headerParam.typeName();
-            headerTypeSchema = handleReference(semanticModel, components, refNode);
+            headerTypeSchema = handleReference(semanticModel, components, refNode, moduleMemberVisitor);
         } else {
             headerTypeSchema = ConverterCommonUtils.getOpenApiSchema(getHeaderType(headerParam));
         }
@@ -184,7 +187,7 @@ private void completeHeaderParameter(List parameters, String headerNa
             Schema itemSchema;
             if (kind == SyntaxKind.SIMPLE_NAME_REFERENCE) {
                 SimpleNameReferenceNode refNode = (SimpleNameReferenceNode) arrayNode.memberTypeDesc();
-                itemSchema = handleReference(semanticModel, components, refNode);
+                itemSchema = handleReference(semanticModel, components, refNode, moduleMemberVisitor);
             } else {
                 itemSchema = ConverterCommonUtils.getOpenApiSchema(kind);
             }
diff --git a/openapi-bal-service/src/main/java/io/ballerina/openapi/converter/service/OpenAPIParameterMapper.java b/openapi-bal-service/src/main/java/io/ballerina/openapi/converter/service/OpenAPIParameterMapper.java
index bad38bb07..cfb686174 100644
--- a/openapi-bal-service/src/main/java/io/ballerina/openapi/converter/service/OpenAPIParameterMapper.java
+++ b/openapi-bal-service/src/main/java/io/ballerina/openapi/converter/service/OpenAPIParameterMapper.java
@@ -58,6 +58,7 @@
 import static io.ballerina.openapi.converter.Constants.WILD_CARD_CONTENT_KEY;
 import static io.ballerina.openapi.converter.Constants.WILD_CARD_SUMMARY;
 import static io.ballerina.openapi.converter.utils.ConverterCommonUtils.extractCustomMediaType;
+import static io.ballerina.openapi.converter.utils.ConverterCommonUtils.unescapeIdentifier;
 
 /**
  * OpenAPIParameterMapper provides functionality for converting ballerina parameter to OAS parameter model.
@@ -69,6 +70,7 @@ public class OpenAPIParameterMapper {
     private final List errors = new ArrayList<>();
     private final Components components;
     private final SemanticModel semanticModel;
+    private final ModuleMemberVisitor moduleMemberVisitor;
 
     public List getErrors() {
         return errors;
@@ -76,13 +78,15 @@ public List getErrors() {
 
     public OpenAPIParameterMapper(FunctionDefinitionNode functionDefinitionNode,
                                   OperationAdaptor operationAdaptor, Map apidocs,
-                                  Components components, SemanticModel semanticModel) {
+                                  Components components, SemanticModel semanticModel,
+                                  ModuleMemberVisitor moduleMemberVisitor) {
 
         this.functionDefinitionNode = functionDefinitionNode;
         this.operationAdaptor = operationAdaptor;
         this.apidocs = apidocs;
         this.components = components;
         this.semanticModel = semanticModel;
+        this.moduleMemberVisitor = moduleMemberVisitor;
     }
 
 
@@ -100,7 +104,7 @@ public void getResourceInputs(Components components, SemanticModel semanticModel
         SeparatedNodeList parameterList = functionSignature.parameters();
         for (ParameterNode parameterNode : parameterList) {
             OpenAPIQueryParameterMapper queryParameterMapper = new OpenAPIQueryParameterMapper(apidocs, components,
-                    semanticModel);
+                    semanticModel, moduleMemberVisitor);
             if (parameterNode.kind() == SyntaxKind.REQUIRED_PARAM) {
                 RequiredParameterNode requiredParameterNode = (RequiredParameterNode) parameterNode;
                 // Handle query parameter
@@ -159,11 +163,12 @@ private void createPathParameters(List parameters, NodeList pat
                 ResourcePathParameterNode pathParam = (ResourcePathParameterNode) param;
                 if (pathParam.typeDescriptor().kind() == SyntaxKind.SIMPLE_NAME_REFERENCE) {
                     SimpleNameReferenceNode queryNode = (SimpleNameReferenceNode) pathParam.typeDescriptor();
-                    OpenAPIComponentMapper componentMapper = new OpenAPIComponentMapper(components);
+                    OpenAPIComponentMapper componentMapper = new OpenAPIComponentMapper(components,
+                            moduleMemberVisitor);
                     TypeSymbol typeSymbol = (TypeSymbol) semanticModel.symbol(queryNode).orElseThrow();
                     componentMapper.createComponentSchema(components.getSchemas(), typeSymbol);
                     Schema schema = new Schema();
-                    schema.set$ref(ConverterCommonUtils.unescapeIdentifier(queryNode.name().text().trim()));
+                    schema.set$ref(unescapeIdentifier(queryNode.name().text().trim()));
                     pathParameterOAS.setSchema(schema);
                 } else {
                     pathParameterOAS.schema(ConverterCommonUtils.getOpenApiSchema(
@@ -195,12 +200,13 @@ private void handleAnnotationParameters(Components components,
         for (AnnotationNode annotation: annotations) {
             if ((annotation.annotReference().toString()).trim().equals(Constants.HTTP_HEADER)) {
                 // Handle headers.
-                OpenAPIHeaderMapper openAPIHeaderMapper = new OpenAPIHeaderMapper(components, semanticModel, apidocs);
+                OpenAPIHeaderMapper openAPIHeaderMapper = new OpenAPIHeaderMapper(components, semanticModel, apidocs,
+                        moduleMemberVisitor);
                 parameters.addAll(openAPIHeaderMapper.setHeaderParameter(requiredParameterNode));
             } else if ((annotation.annotReference().toString()).trim().equals(Constants.HTTP_QUERY)) {
                 // Handle query parameter.
                 OpenAPIQueryParameterMapper openAPIQueryParameterMapper = new OpenAPIQueryParameterMapper(apidocs,
-                        components, semanticModel);
+                        components, semanticModel, moduleMemberVisitor);
                 parameters.add(openAPIQueryParameterMapper.createQueryParameter(requiredParameterNode));
             } else if ((annotation.annotReference().toString()).trim().equals(Constants.HTTP_PAYLOAD) &&
                     (!Constants.GET.toLowerCase(Locale.ENGLISH).equalsIgnoreCase(
@@ -210,8 +216,9 @@ private void handleAnnotationParameters(Components components,
                 Optional customMediaType = extractCustomMediaType(functionDefinitionNode);
                 OpenAPIRequestBodyMapper openAPIRequestBodyMapper = customMediaType.map(
                         value -> new OpenAPIRequestBodyMapper(components,
-                        operationAdaptor, semanticModel, value)).orElse(new OpenAPIRequestBodyMapper(components,
-                        operationAdaptor, semanticModel));
+                        operationAdaptor, semanticModel, value, moduleMemberVisitor)).orElse(
+                                new OpenAPIRequestBodyMapper(components,
+                        operationAdaptor, semanticModel, moduleMemberVisitor));
                 openAPIRequestBodyMapper.handlePayloadAnnotation(requiredParameterNode, schema, annotation, apidocs);
                 errors.addAll(openAPIRequestBodyMapper.getDiagnostics());
             } else if ((annotation.annotReference().toString()).trim().equals(Constants.HTTP_PAYLOAD) &&
@@ -233,12 +240,13 @@ private List handleDefaultableAnnotationParameters(DefaultableParamet
         for (AnnotationNode annotation: annotations) {
             if ((annotation.annotReference().toString()).trim().equals(Constants.HTTP_HEADER)) {
                 // Handle headers.
-                OpenAPIHeaderMapper openAPIHeaderMapper = new OpenAPIHeaderMapper(components, semanticModel, apidocs);
+                OpenAPIHeaderMapper openAPIHeaderMapper = new OpenAPIHeaderMapper(components, semanticModel, apidocs,
+                        moduleMemberVisitor);
                 parameters = openAPIHeaderMapper.setHeaderParameter(defaultableParameterNode);
             } else if ((annotation.annotReference().toString()).trim().equals(Constants.HTTP_QUERY)) {
                 // Handle query parameter.
                 OpenAPIQueryParameterMapper openAPIQueryParameterMapper = new OpenAPIQueryParameterMapper(apidocs,
-                        components, semanticModel);
+                        components, semanticModel, moduleMemberVisitor);
                 parameters.add(openAPIQueryParameterMapper.createQueryParameter(defaultableParameterNode));
             }
         }
diff --git a/openapi-bal-service/src/main/java/io/ballerina/openapi/converter/service/OpenAPIQueryParameterMapper.java b/openapi-bal-service/src/main/java/io/ballerina/openapi/converter/service/OpenAPIQueryParameterMapper.java
index d7578d3da..b70abfec4 100644
--- a/openapi-bal-service/src/main/java/io/ballerina/openapi/converter/service/OpenAPIQueryParameterMapper.java
+++ b/openapi-bal-service/src/main/java/io/ballerina/openapi/converter/service/OpenAPIQueryParameterMapper.java
@@ -54,10 +54,10 @@
 import static io.ballerina.compiler.syntax.tree.SyntaxKind.SIMPLE_NAME_REFERENCE;
 import static io.ballerina.compiler.syntax.tree.SyntaxKind.STRING_LITERAL;
 import static io.ballerina.openapi.converter.utils.ConverterCommonUtils.getAnnotationNodesFromServiceNode;
+import static io.ballerina.openapi.converter.utils.ConverterCommonUtils.getOpenApiSchema;
 import static io.ballerina.openapi.converter.utils.ConverterCommonUtils.handleReference;
 import static io.ballerina.openapi.converter.utils.ConverterCommonUtils.unescapeIdentifier;
 
-
 /**
  * This class processes mapping query parameters in between Ballerina and OAS.
  *
@@ -67,14 +67,16 @@ public class OpenAPIQueryParameterMapper {
     private final Components components;
     private final SemanticModel semanticModel;
     private final Map apidocs;
+    private final ModuleMemberVisitor moduleMemberVisitor;
     private final SyntaxKind[] validExpressionKind = {STRING_LITERAL, NUMERIC_LITERAL, BOOLEAN_LITERAL,
             LIST_CONSTRUCTOR, NIL_LITERAL, MAPPING_CONSTRUCTOR};
 
     public OpenAPIQueryParameterMapper(Map apidocs, Components components,
-                                       SemanticModel semanticModel) {
+                                       SemanticModel semanticModel, ModuleMemberVisitor moduleMemberVisitor) {
         this.apidocs = apidocs;
         this.components = components;
         this.semanticModel = semanticModel;
+        this.moduleMemberVisitor = moduleMemberVisitor;
     }
 
     /**
@@ -87,7 +89,7 @@ public Parameter createQueryParameter(RequiredParameterNode queryParam) {
         if (queryParam.typeName() instanceof BuiltinSimpleNameReferenceNode && isQuery) {
             QueryParameter queryParameter = new QueryParameter();
             queryParameter.setName(unescapeIdentifier(queryParamName));
-            Schema openApiSchema = ConverterCommonUtils.getOpenApiSchema(queryParam.typeName().toString().trim());
+            Schema openApiSchema = getOpenApiSchema(queryParam.typeName().toString().trim());
             queryParameter.setSchema(openApiSchema);
             queryParameter.setRequired(true);
             if (!apidocs.isEmpty() && queryParam.paramName().isPresent() && apidocs.containsKey(queryParamName)) {
@@ -115,7 +117,8 @@ public Parameter createQueryParameter(RequiredParameterNode queryParam) {
             QueryParameter queryParameter = new QueryParameter();
             queryParameter.setName(unescapeIdentifier(queryParamName));
             SimpleNameReferenceNode queryNode = (SimpleNameReferenceNode) queryParam.typeName();
-            OpenAPIComponentMapper componentMapper = new OpenAPIComponentMapper(components);
+            OpenAPIComponentMapper componentMapper = new OpenAPIComponentMapper(components, moduleMemberVisitor);
+
             TypeSymbol typeSymbol = (TypeSymbol) semanticModel.symbol(queryNode).orElseThrow();
             componentMapper.createComponentSchema(components.getSchemas(), typeSymbol);
             Schema schema = new Schema<>();
@@ -129,7 +132,7 @@ public Parameter createQueryParameter(RequiredParameterNode queryParam) {
         } else if (queryParam.typeName().kind() == SIMPLE_NAME_REFERENCE) {
             QueryParameter queryParameter = new QueryParameter();
             Schema refSchema = handleReference(semanticModel, components, (SimpleNameReferenceNode)
-                    queryParam.typeName());
+                    queryParam.typeName(), moduleMemberVisitor);
             queryParameter.setSchema(refSchema);
             queryParameter.setRequired(true);
             if (!apidocs.isEmpty() && apidocs.containsKey(queryParamName)) {
@@ -157,7 +160,7 @@ public Parameter createQueryParameter(DefaultableParameterNode defaultableQueryP
         QueryParameter queryParameter = new QueryParameter();
         if (defaultableQueryParam.typeName() instanceof BuiltinSimpleNameReferenceNode && isQuery) {
             queryParameter.setName(unescapeIdentifier(queryParamName));
-            Schema openApiSchema = ConverterCommonUtils.getOpenApiSchema(
+            Schema openApiSchema = getOpenApiSchema(
                     defaultableQueryParam.typeName().toString().trim());
             queryParameter.setSchema(openApiSchema);
             if (!apidocs.isEmpty() && defaultableQueryParam.paramName().isPresent() &&
@@ -176,7 +179,7 @@ public Parameter createQueryParameter(DefaultableParameterNode defaultableQueryP
         } else if (defaultableQueryParam.typeName().kind() == SIMPLE_NAME_REFERENCE) {
             queryParameter.setName(unescapeIdentifier(queryParamName));
             Schema refSchema = handleReference(semanticModel, components,
-                    (SimpleNameReferenceNode) defaultableQueryParam.typeName());
+                    (SimpleNameReferenceNode) defaultableQueryParam.typeName(), moduleMemberVisitor);
             queryParameter.setSchema(refSchema);
             queryParameter.setRequired(true);
             if (!apidocs.isEmpty() && apidocs.containsKey(queryParamName)) {
@@ -224,13 +227,13 @@ private QueryParameter handleArrayTypeQueryParameter(String queryParamName, Arra
         TypeDescriptorNode itemTypeNode = arrayNode.memberTypeDesc();
         Schema itemSchema;
         if (arrayNode.memberTypeDesc().kind() == OPTIONAL_TYPE_DESC) {
-            itemSchema = ConverterCommonUtils.getOpenApiSchema(
+            itemSchema = getOpenApiSchema(
                     ((OptionalTypeDescriptorNode) itemTypeNode).typeDescriptor().toString().trim());
             itemSchema.setNullable(true);
         } else if (arrayNode.memberTypeDesc().kind() == SIMPLE_NAME_REFERENCE) {
             itemSchema = getItemSchemaForReference(arrayNode);
         } else {
-            itemSchema = ConverterCommonUtils.getOpenApiSchema(itemTypeNode.toString().trim());
+            itemSchema = getOpenApiSchema(itemTypeNode.toString().trim());
         }
         arraySchema.setItems(itemSchema);
         queryParameter.schema(arraySchema);
@@ -243,7 +246,7 @@ private QueryParameter handleArrayTypeQueryParameter(String queryParamName, Arra
 
     private Schema getItemSchemaForReference(ArrayTypeDescriptorNode arrayNode) {
         SimpleNameReferenceNode record = (SimpleNameReferenceNode) arrayNode.memberTypeDesc();
-        return handleReference(semanticModel, components, record);
+        return handleReference(semanticModel, components, record, moduleMemberVisitor);
     }
 
     /**
@@ -267,7 +270,7 @@ private QueryParameter setOptionalQueryParameter(String queryParamName, Optional
             if (arrayNode.memberTypeDesc().kind() == SIMPLE_NAME_REFERENCE) {
                 itemSchema = getItemSchemaForReference(arrayNode);
             } else {
-                itemSchema = ConverterCommonUtils.getOpenApiSchema(itemTypeNode.toString().trim());
+                itemSchema = getOpenApiSchema(itemTypeNode.toString().trim());
             }
             arraySchema.setItems(itemSchema);
             queryParameter.schema(arraySchema);
@@ -286,7 +289,8 @@ private QueryParameter setOptionalQueryParameter(String queryParamName, Optional
             }
             return queryParameter;
         } else if (node.kind() == SIMPLE_NAME_REFERENCE) {
-            Schema refSchema = handleReference(semanticModel, components, (SimpleNameReferenceNode) node);
+            Schema refSchema = handleReference(semanticModel, components, (SimpleNameReferenceNode) node,
+                    moduleMemberVisitor);
             queryParameter.setSchema(refSchema);
             if (isOptional.equals(Constants.FALSE)) {
                 queryParameter.setRequired(true);
@@ -296,7 +300,7 @@ private QueryParameter setOptionalQueryParameter(String queryParamName, Optional
             }
             return queryParameter;
         } else {
-            Schema openApiSchema = ConverterCommonUtils.getOpenApiSchema(node.toString().trim());
+            Schema openApiSchema = getOpenApiSchema(node.toString().trim());
             openApiSchema.setNullable(true);
             queryParameter.setSchema(openApiSchema);
             if (!apidocs.isEmpty() && apidocs.containsKey(queryParamName)) {
diff --git a/openapi-bal-service/src/main/java/io/ballerina/openapi/converter/service/OpenAPIRequestBodyMapper.java b/openapi-bal-service/src/main/java/io/ballerina/openapi/converter/service/OpenAPIRequestBodyMapper.java
index 8a278cbe3..23fc64451 100644
--- a/openapi-bal-service/src/main/java/io/ballerina/openapi/converter/service/OpenAPIRequestBodyMapper.java
+++ b/openapi-bal-service/src/main/java/io/ballerina/openapi/converter/service/OpenAPIRequestBodyMapper.java
@@ -82,6 +82,7 @@ public class OpenAPIRequestBodyMapper {
     private final SemanticModel semanticModel;
     private final String customMediaPrefix;
     private final List diagnostics;
+    private final ModuleMemberVisitor moduleMemberVisitor;
 
     /**
      * This constructor uses to create OpenAPIRequestBodyMapper instance when customMedia type enable.
@@ -92,12 +93,14 @@ public class OpenAPIRequestBodyMapper {
      * @param customMediaType   - custom media type
      */
     public OpenAPIRequestBodyMapper(Components components, OperationAdaptor operationAdaptor,
-                                    SemanticModel semanticModel, String customMediaType) {
+                                    SemanticModel semanticModel, String customMediaType,
+                                    ModuleMemberVisitor moduleMemberVisitor) {
         this.components = components;
         this.operationAdaptor = operationAdaptor;
         this.semanticModel = semanticModel;
         this.customMediaPrefix = customMediaType;
         this.diagnostics = new ArrayList<>();
+        this.moduleMemberVisitor = moduleMemberVisitor;
     }
 
     /**
@@ -108,8 +111,8 @@ public OpenAPIRequestBodyMapper(Components components, OperationAdaptor operatio
      * @param semanticModel     - Semantic model for given ballerina service
      */
     public OpenAPIRequestBodyMapper(Components components, OperationAdaptor operationAdaptor,
-                                    SemanticModel semanticModel) {
-        this(components, operationAdaptor, semanticModel, null);
+                                    SemanticModel semanticModel, ModuleMemberVisitor moduleMemberVisitor) {
+        this(components, operationAdaptor, semanticModel, null, moduleMemberVisitor);
     }
 
     public List getDiagnostics() {
@@ -125,7 +128,6 @@ public List getDiagnostics() {
      */
     public void handlePayloadAnnotation(RequiredParameterNode payloadNode, Map schema,
                                         AnnotationNode annotation, Map apiDocs) {
-
         if ((annotation.annotReference().toString()).trim().equals(Constants.HTTP_PAYLOAD)) {
             // Creating request body - required.
             RequestBody bodyParameter = new RequestBody();
@@ -165,97 +167,101 @@ private void handlePayloadType(TypeDescriptorNode payloadNode, Map openApiSchema = getOpenApiSchema(mapMemberType);
-                    objectSchema.additionalProperties(openApiSchema);
-                    io.swagger.v3.oas.models.media.MediaType mediaType = new io.swagger.v3.oas.models.media.MediaType();
-                    if (bodyParameter.getContent() != null) {
-                        Content content = bodyParameter.getContent();
-                        if (content.containsKey(mediaTypeString)) {
-                            ComposedSchema oneOfSchema = new ComposedSchema();
-                            oneOfSchema.addOneOfItem(content.get(mediaTypeString).getSchema());
-                            oneOfSchema.addOneOfItem(objectSchema);
-                            mediaType.setSchema(oneOfSchema);
-                            content.addMediaType(mediaTypeString, mediaType);
-                        } else {
-                            mediaType.setSchema(objectSchema);
-                            content.addMediaType(mediaTypeString, mediaType);
-                        }
+        if (!isTypeDeclarationExtractable(kind, mediaTypeString)) {
+            //Warning message for unsupported request payload type in Ballerina resource.
+            IncompatibleResourceDiagnostic error = new IncompatibleResourceDiagnostic(
+                    DiagnosticMessages.OAS_CONVERTOR_117, payloadNode.location(), payloadNode.toSourceCode().trim());
+            diagnostics.add(error);
+            return;
+        }
+        switch (kind) {
+            case INT_TYPE_DESC:
+            case FLOAT_TYPE_DESC:
+            case DECIMAL_TYPE_DESC:
+            case BOOLEAN_TYPE_DESC:
+            case JSON_TYPE_DESC:
+            case XML_TYPE_DESC:
+            case BYTE_TYPE_DESC:
+                addConsumes(operationAdaptor, bodyParameter, mediaTypeString, kind);
+                break;
+            case STRING_TYPE_DESC:
+                mediaTypeString = customMediaPrefix == null ? MediaType.TEXT_PLAIN :
+                        TEXT_PREFIX + customMediaPrefix + TEXT_POSTFIX;
+                addConsumes(operationAdaptor, bodyParameter, mediaTypeString, kind);
+                break;
+            case MAP_TYPE_DESC:
+                Schema objectSchema = new ObjectSchema();
+                MapTypeDescriptorNode mapTypeDescriptorNode = (MapTypeDescriptorNode) payloadNode;
+                SyntaxKind mapMemberType = (mapTypeDescriptorNode.mapTypeParamsNode()).typeNode().kind();
+                Schema openApiSchema = getOpenApiSchema(mapMemberType);
+                objectSchema.additionalProperties(openApiSchema);
+                io.swagger.v3.oas.models.media.MediaType mediaType = new io.swagger.v3.oas.models.media.MediaType();
+                if (bodyParameter.getContent() != null) {
+                    Content content = bodyParameter.getContent();
+                    if (content.containsKey(mediaTypeString)) {
+                        ComposedSchema oneOfSchema = new ComposedSchema();
+                        oneOfSchema.addOneOfItem(content.get(mediaTypeString).getSchema());
+                        oneOfSchema.addOneOfItem(objectSchema);
+                        mediaType.setSchema(oneOfSchema);
+                        content.addMediaType(mediaTypeString, mediaType);
                     } else {
                         mediaType.setSchema(objectSchema);
-                        bodyParameter.setContent(new Content().addMediaType(mediaTypeString, mediaType));
+                        content.addMediaType(mediaTypeString, mediaType);
                     }
-                    operationAdaptor.getOperation().setRequestBody(bodyParameter);
-                    break;
-                case OPTIONAL_TYPE_DESC:
-                    OptionalTypeDescriptorNode optionalTypeDescriptorNode = (OptionalTypeDescriptorNode) payloadNode;
-                    handlePayloadType((TypeDescriptorNode) optionalTypeDescriptorNode.typeDescriptor(),
-                            schema, bodyParameter);
-                    break;
-                case UNION_TYPE_DESC:
-                    UnionTypeDescriptorNode unionTypeDescriptorNode = (UnionTypeDescriptorNode) payloadNode;
-                    TypeDescriptorNode leftTypeDesc = unionTypeDescriptorNode.leftTypeDesc();
-                    TypeDescriptorNode rightTypeDesc = unionTypeDescriptorNode.rightTypeDesc();
-                    handlePayloadType(leftTypeDesc, schema, bodyParameter);
-                    handlePayloadType(rightTypeDesc, schema, bodyParameter);
-                    break;
-                case SIMPLE_NAME_REFERENCE:
-                    SimpleNameReferenceNode record = (SimpleNameReferenceNode) payloadNode;
-                    TypeSymbol typeSymbol = getReferenceTypeSymbol(semanticModel.symbol(record));
-                    String recordName = record.name().toString().trim();
-                    handleReferencePayload(typeSymbol, mediaTypeString, recordName, schema, bodyParameter);
-                    break;
-                case QUALIFIED_NAME_REFERENCE:
-                    QualifiedNameReferenceNode separateRecord = (QualifiedNameReferenceNode) payloadNode;
-                    typeSymbol = getReferenceTypeSymbol(semanticModel.symbol(separateRecord));
-                    recordName = ((QualifiedNameReferenceNode) payloadNode).identifier().text();
-                    TypeDescKind typeDesc = ((TypeReferenceTypeSymbol) typeSymbol).typeDescriptor().typeKind();
-                    String mimeType = getMediaTypeForTypeDecKind(typeDesc);
+                } else {
+                    mediaType.setSchema(objectSchema);
+                    bodyParameter.setContent(new Content().addMediaType(mediaTypeString, mediaType));
+                }
+                operationAdaptor.getOperation().setRequestBody(bodyParameter);
+                break;
+            case OPTIONAL_TYPE_DESC:
+                OptionalTypeDescriptorNode optionalTypeDescriptorNode = (OptionalTypeDescriptorNode) payloadNode;
+                handlePayloadType((TypeDescriptorNode) optionalTypeDescriptorNode.typeDescriptor(),
+                        schema, bodyParameter);
+                break;
+            case UNION_TYPE_DESC:
+                UnionTypeDescriptorNode unionTypeDescriptorNode = (UnionTypeDescriptorNode) payloadNode;
+                TypeDescriptorNode leftTypeDesc = unionTypeDescriptorNode.leftTypeDesc();
+                TypeDescriptorNode rightTypeDesc = unionTypeDescriptorNode.rightTypeDesc();
+                handlePayloadType(leftTypeDesc, schema, bodyParameter);
+                handlePayloadType(rightTypeDesc, schema, bodyParameter);
+                break;
+            case SIMPLE_NAME_REFERENCE:
+                SimpleNameReferenceNode record = (SimpleNameReferenceNode) payloadNode;
+                TypeSymbol typeSymbol = getReferenceTypeSymbol(semanticModel.symbol(record));
+                String recordName = record.name().toString().trim();
+                handleReferencePayload(typeSymbol, mediaTypeString, recordName, schema, bodyParameter);
+                break;
+            case QUALIFIED_NAME_REFERENCE:
+                QualifiedNameReferenceNode separateRecord = (QualifiedNameReferenceNode) payloadNode;
+                typeSymbol = getReferenceTypeSymbol(semanticModel.symbol(separateRecord));
+                recordName = ((QualifiedNameReferenceNode) payloadNode).identifier().text();
+                TypeDescKind typeDesc = ((TypeReferenceTypeSymbol) typeSymbol).typeDescriptor().typeKind();
+                String mimeType = getMediaTypeForTypeDecKind(typeDesc);
 
-                    handleReferencePayload(typeSymbol, mimeType, recordName, schema, bodyParameter);
-                    break;
-                case ARRAY_TYPE_DESC:
-                    ArrayTypeDescriptorNode arrayNode = (ArrayTypeDescriptorNode) payloadNode;
-                    mediaTypeString = getMediaTypeForSyntaxKind(arrayNode.memberTypeDesc());
-                    handleArrayTypePayload(schema, arrayNode, mediaTypeString, bodyParameter);
-                    break;
-                default:
-                    //Warning message for unsupported request payload type in Ballerina resource.
-                    IncompatibleResourceDiagnostic error = new IncompatibleResourceDiagnostic(
-                            DiagnosticMessages.OAS_CONVERTOR_116, payloadNode.location(),
-                            String.valueOf(payloadNode.kind()));
-                    diagnostics.add(error);
-                    break;
-            }
-        } else {
-            //Warning message for unsupported request payload type in Ballerina resource.
-            IncompatibleResourceDiagnostic error = new IncompatibleResourceDiagnostic(
-                    DiagnosticMessages.OAS_CONVERTOR_116, payloadNode.location(), payloadNode.toSourceCode().trim());
-            diagnostics.add(error);
+                handleReferencePayload(typeSymbol, mimeType, recordName, schema, bodyParameter);
+                break;
+            case ARRAY_TYPE_DESC:
+                ArrayTypeDescriptorNode arrayNode = (ArrayTypeDescriptorNode) payloadNode;
+                mediaTypeString = getMediaTypeForSyntaxKind(arrayNode.memberTypeDesc());
+                handleArrayTypePayload(schema, arrayNode, mediaTypeString, bodyParameter);
+                break;
+            default:
+                //Warning message for unsupported request payload type in Ballerina resource.
+                IncompatibleResourceDiagnostic error = new IncompatibleResourceDiagnostic(
+                        DiagnosticMessages.OAS_CONVERTOR_117, payloadNode.location(),
+                        payloadNode.toSourceCode().trim());
+                diagnostics.add(error);
+                break;
         }
     }
 
+    private static boolean isTypeDeclarationExtractable(SyntaxKind kind, String mediaTypeString) {
+        return mediaTypeString != null || kind == SyntaxKind.UNION_TYPE_DESC ||
+                kind == SyntaxKind.QUALIFIED_NAME_REFERENCE || kind == SyntaxKind.OPTIONAL_TYPE_DESC ||
+                kind == SyntaxKind.ARRAY_TYPE_DESC;
+    }
+
     /**
      * This function is used to select the media type according to the syntax kind.
      *
@@ -350,7 +356,7 @@ private void handleArrayTypePayload(Map schema, ArrayTypeDescrip
                 typeDescriptorNode.kind().equals(SyntaxKind.QUALIFIED_NAME_REFERENCE)) {
             //handle record for components
             TypeSymbol typeSymbol = getReferenceTypeSymbol(semanticModel.symbol(typeDescriptorNode));
-            OpenAPIComponentMapper componentMapper = new OpenAPIComponentMapper(components);
+            OpenAPIComponentMapper componentMapper = new OpenAPIComponentMapper(components, moduleMemberVisitor);
             componentMapper.createComponentSchema(schema, typeSymbol);
             diagnostics.addAll(componentMapper.getDiagnostics());
             Schema itemSchema = new Schema();
@@ -427,7 +433,7 @@ private void createRequestBody(RequestBody bodyParameter, RequiredParameterNode
     private void handleReferencePayload(TypeSymbol typeSymbol, String mediaType, String recordName,
                                         Map schema, RequestBody bodyParameter) {
         //handle record for components
-        OpenAPIComponentMapper componentMapper = new OpenAPIComponentMapper(components);
+        OpenAPIComponentMapper componentMapper = new OpenAPIComponentMapper(components, moduleMemberVisitor);
         componentMapper.createComponentSchema(schema, typeSymbol);
         diagnostics.addAll(componentMapper.getDiagnostics());
         io.swagger.v3.oas.models.media.MediaType media = new io.swagger.v3.oas.models.media.MediaType();
diff --git a/openapi-bal-service/src/main/java/io/ballerina/openapi/converter/service/OpenAPIResourceMapper.java b/openapi-bal-service/src/main/java/io/ballerina/openapi/converter/service/OpenAPIResourceMapper.java
index 517bfcb47..44d0a92ca 100644
--- a/openapi-bal-service/src/main/java/io/ballerina/openapi/converter/service/OpenAPIResourceMapper.java
+++ b/openapi-bal-service/src/main/java/io/ballerina/openapi/converter/service/OpenAPIResourceMapper.java
@@ -59,6 +59,7 @@
  */
 public class OpenAPIResourceMapper {
     private final SemanticModel semanticModel;
+    private final ModuleMemberVisitor moduleMemberVisitor;
     private final Paths pathObject = new Paths();
     private final Components components = new Components();
     private final List errors;
@@ -70,9 +71,10 @@ public List getErrors() {
     /**
      * Initializes a resource parser for openApi.
      */
-    OpenAPIResourceMapper(SemanticModel semanticModel) {
+    OpenAPIResourceMapper(SemanticModel semanticModel, ModuleMemberVisitor moduleMemberVisitor) {
         this.semanticModel = semanticModel;
         this.errors = new ArrayList<>();
+        this.moduleMemberVisitor = moduleMemberVisitor;
     }
 
     public Components getComponents() {
@@ -212,7 +214,7 @@ private Optional convertResourceToOperation(FunctionDefinition
         Map apiDocs = listAPIDocumentations(resource, op);
         //Add path parameters if in path and query parameters
         OpenAPIParameterMapper openAPIParameterMapper = new OpenAPIParameterMapper(resource, op, apiDocs, components,
-                semanticModel);
+                semanticModel, moduleMemberVisitor);
         openAPIParameterMapper.getResourceInputs(components, semanticModel);
         if (openAPIParameterMapper.getErrors().size() > 1 || (openAPIParameterMapper.getErrors().size() == 1 &&
                 !openAPIParameterMapper.getErrors().get(0).getCode().equals("OAS_CONVERTOR_113"))) {
@@ -226,7 +228,7 @@ private Optional convertResourceToOperation(FunctionDefinition
         errors.addAll(openAPIParameterMapper.getErrors());
 
         OpenAPIResponseMapper openAPIResponseMapper = new OpenAPIResponseMapper(semanticModel, components,
-                resource.location());
+                resource.location(), moduleMemberVisitor);
         openAPIResponseMapper.getResourceOutput(resource, op);
         if (!openAPIResponseMapper.getErrors().isEmpty()) {
             errors.addAll(openAPIResponseMapper.getErrors());
diff --git a/openapi-bal-service/src/main/java/io/ballerina/openapi/converter/service/OpenAPIResponseMapper.java b/openapi-bal-service/src/main/java/io/ballerina/openapi/converter/service/OpenAPIResponseMapper.java
index c10a14045..42b9ebda0 100644
--- a/openapi-bal-service/src/main/java/io/ballerina/openapi/converter/service/OpenAPIResponseMapper.java
+++ b/openapi-bal-service/src/main/java/io/ballerina/openapi/converter/service/OpenAPIResponseMapper.java
@@ -157,15 +157,18 @@ public class OpenAPIResponseMapper {
     private final List errors = new ArrayList<>();
     private final Location location;
     private String httpMethod;
+    private ModuleMemberVisitor moduleMemberVisitor;
 
     public List getErrors() {
         return errors;
     }
 
-    public OpenAPIResponseMapper(SemanticModel semanticModel, Components components, Location location) {
+    public OpenAPIResponseMapper(SemanticModel semanticModel, Components components, Location location,
+                                 ModuleMemberVisitor moduleMemberVisitor) {
         this.semanticModel = semanticModel;
         this.components = components;
         this.location = location;
+        this.moduleMemberVisitor = moduleMemberVisitor;
     }
 
     /**
@@ -604,7 +607,8 @@ private Optional handleQualifiedNameType(ApiResponses apiResponses
                 }
                 if (typeSymbol.typeKind() == TypeDescKind.RECORD) {
                     ApiResponses responses = handleRecordTypeSymbol(qNode.identifier().text().trim(),
-                            components.getSchemas(), customMediaPrefix, typeRef, new OpenAPIComponentMapper(components),
+                            components.getSchemas(), customMediaPrefix, typeRef,
+                            new OpenAPIComponentMapper(components, moduleMemberVisitor),
                             headers);
                     apiResponses.putAll(responses);
                     return Optional.of(apiResponses);
@@ -901,7 +905,7 @@ private void handleReferenceResponse(OperationAdaptor operationAdaptor, SimpleNa
         Optional symbol = semanticModel.symbol(referenceNode);
         TypeSymbol typeSymbol = (TypeSymbol) symbol.orElseThrow();
         //handle record for components
-        OpenAPIComponentMapper componentMapper = new OpenAPIComponentMapper(components);
+        OpenAPIComponentMapper componentMapper = new OpenAPIComponentMapper(components, moduleMemberVisitor);
         String mediaTypeString;
         // Check typeInclusion is related to the http status code
         if (referenceNode.parent().kind().equals(ARRAY_TYPE_DESC)) {
diff --git a/openapi-bal-service/src/main/java/io/ballerina/openapi/converter/service/OpenAPIServiceMapper.java b/openapi-bal-service/src/main/java/io/ballerina/openapi/converter/service/OpenAPIServiceMapper.java
index a7fc0d9aa..a7d7cbf62 100644
--- a/openapi-bal-service/src/main/java/io/ballerina/openapi/converter/service/OpenAPIServiceMapper.java
+++ b/openapi-bal-service/src/main/java/io/ballerina/openapi/converter/service/OpenAPIServiceMapper.java
@@ -39,6 +39,7 @@
  */
 public class OpenAPIServiceMapper {
     private final SemanticModel semanticModel;
+    private final ModuleMemberVisitor moduleMemberVisitor;
     private final List errors = new ArrayList<>();
 
     public List getErrors() {
@@ -48,9 +49,10 @@ public List getErrors() {
     /**
      * Initializes a service parser for OpenApi.
      */
-    public OpenAPIServiceMapper(SemanticModel semanticModel) {
+    public OpenAPIServiceMapper(SemanticModel semanticModel, ModuleMemberVisitor moduleMemberVisitor) {
         // Default object mapper is JSON mapper available in openApi utils.
         this.semanticModel = semanticModel;
+        this.moduleMemberVisitor = moduleMemberVisitor;
     }
 
     /**
@@ -69,7 +71,7 @@ public OpenAPI convertServiceToOpenAPI(ServiceDeclarationNode service, OpenAPI o
                 resource.add((FunctionDefinitionNode) function);
             }
         }
-        OpenAPIResourceMapper resourceMapper = new OpenAPIResourceMapper(this.semanticModel);
+        OpenAPIResourceMapper resourceMapper = new OpenAPIResourceMapper(this.semanticModel, this.moduleMemberVisitor);
         openapi.setPaths(resourceMapper.getPaths(resource));
         openapi.setComponents(resourceMapper.getComponents());
         errors.addAll(resourceMapper.getErrors());
diff --git a/openapi-bal-service/src/main/java/io/ballerina/openapi/converter/utils/ConverterCommonUtils.java b/openapi-bal-service/src/main/java/io/ballerina/openapi/converter/utils/ConverterCommonUtils.java
index c9f9b032f..009e29c6d 100644
--- a/openapi-bal-service/src/main/java/io/ballerina/openapi/converter/utils/ConverterCommonUtils.java
+++ b/openapi-bal-service/src/main/java/io/ballerina/openapi/converter/utils/ConverterCommonUtils.java
@@ -52,6 +52,7 @@
 import io.ballerina.openapi.converter.diagnostic.ExceptionDiagnostic;
 import io.ballerina.openapi.converter.diagnostic.OpenAPIConverterDiagnostic;
 import io.ballerina.openapi.converter.model.OASResult;
+import io.ballerina.openapi.converter.service.ModuleMemberVisitor;
 import io.ballerina.openapi.converter.service.OpenAPIComponentMapper;
 import io.ballerina.runtime.api.utils.IdentifierUtils;
 import io.ballerina.tools.diagnostics.Diagnostic;
@@ -527,13 +528,14 @@ public static String unescapeIdentifier(String parameterName) {
     }
 
     public static Schema handleReference(SemanticModel semanticModel, Components components,
-                                            SimpleNameReferenceNode record) {
+                                            SimpleNameReferenceNode recordNode,
+                                            ModuleMemberVisitor moduleMemberVisitor) {
         Schema refSchema = new Schema<>();
         // Creating request body - required.
-        Optional symbol = semanticModel.symbol(record);
+        Optional symbol = semanticModel.symbol(recordNode);
         if (symbol.isPresent() && symbol.get() instanceof TypeSymbol) {
-            String recordName = record.name().toString().trim();
-            OpenAPIComponentMapper componentMapper = new OpenAPIComponentMapper(components);
+            String recordName = recordNode.name().toString().trim();
+            OpenAPIComponentMapper componentMapper = new OpenAPIComponentMapper(components, moduleMemberVisitor);
             componentMapper.createComponentSchema(components.getSchemas(), (TypeSymbol) symbol.get());
             refSchema.set$ref(ConverterCommonUtils.unescapeIdentifier(recordName));
         }
diff --git a/openapi-bal-service/src/main/java/io/ballerina/openapi/converter/utils/ServiceToOpenAPIConverterUtils.java b/openapi-bal-service/src/main/java/io/ballerina/openapi/converter/utils/ServiceToOpenAPIConverterUtils.java
index 47bbf5768..4d0cf74cf 100644
--- a/openapi-bal-service/src/main/java/io/ballerina/openapi/converter/utils/ServiceToOpenAPIConverterUtils.java
+++ b/openapi-bal-service/src/main/java/io/ballerina/openapi/converter/utils/ServiceToOpenAPIConverterUtils.java
@@ -59,11 +59,11 @@
 import java.nio.file.Paths;
 import java.util.ArrayList;
 import java.util.HashMap;
-import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
 import java.util.Optional;
+import java.util.Set;
 
 import static io.ballerina.openapi.converter.Constants.CONTRACT;
 import static io.ballerina.openapi.converter.Constants.HYPHEN;
@@ -203,7 +203,8 @@ private static void extractServiceNodes(String serviceName, List availab
      */
     public static OASResult generateOAS(OASGenerationMetaInfo oasGenerationMetaInfo) {
         ServiceDeclarationNode serviceDefinition = oasGenerationMetaInfo.getServiceDeclarationNode();
-        LinkedHashSet listeners = collectListeners(oasGenerationMetaInfo.getProject());;
+        ModuleMemberVisitor moduleMemberVisitor = extractNodesFromProject(oasGenerationMetaInfo.getProject());
+        Set listeners = moduleMemberVisitor.getListenerDeclarationNodes();
         SemanticModel semanticModel = oasGenerationMetaInfo.getSemanticModel();
         String openApiFileName = oasGenerationMetaInfo.getOpenApiFileName();
         Path ballerinaFilePath = oasGenerationMetaInfo.getBallerinaFilePath();
@@ -214,7 +215,8 @@ public static OASResult generateOAS(OASGenerationMetaInfo oasGenerationMetaInfo)
             OpenAPI openapi = oasResult.getOpenAPI().get();
             if (openapi.getPaths() == null) {
                 // Take base path of service
-                OpenAPIServiceMapper openAPIServiceMapper = new OpenAPIServiceMapper(semanticModel);
+                OpenAPIServiceMapper openAPIServiceMapper = new OpenAPIServiceMapper(semanticModel,
+                        moduleMemberVisitor);
                 // 02. Filter and set the ServerURLs according to endpoints. Complete the server section in OAS
                 openapi = OpenAPIEndpointMapper.ENDPOINT_MAPPER.getServers(openapi, listeners, serviceDefinition);
                 // 03. Filter path and component sections in OAS.
@@ -489,17 +491,15 @@ private static OASResult resolveContractPath(List di
      *
      * @param project - current project
      */
-    public static LinkedHashSet collectListeners(Project project) {
+    public static ModuleMemberVisitor extractNodesFromProject(Project project) {
         ModuleMemberVisitor balNodeVisitor = new ModuleMemberVisitor();
-        LinkedHashSet listeners = new LinkedHashSet<>();
         project.currentPackage().moduleIds().forEach(moduleId -> {
             Module module = project.currentPackage().module(moduleId);
             module.documentIds().forEach(documentId -> {
                 SyntaxTree syntaxTreeDoc = module.document(documentId).syntaxTree();
                 syntaxTreeDoc.rootNode().accept(balNodeVisitor);
-                listeners.addAll(balNodeVisitor.getListenerDeclarationNodes());
             });
         });
-        return listeners;
+        return balNodeVisitor;
     }
 }
diff --git a/openapi-cli/src/test/java/io/ballerina/openapi/generators/openapi/ConstraintTests.java b/openapi-cli/src/test/java/io/ballerina/openapi/generators/openapi/ConstraintTests.java
new file mode 100644
index 000000000..ff5d0a3bb
--- /dev/null
+++ b/openapi-cli/src/test/java/io/ballerina/openapi/generators/openapi/ConstraintTests.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com).
+ *
+ * WSO2 LLC. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package io.ballerina.openapi.generators.openapi;
+
+import org.testng.annotations.Test;
+
+import java.io.IOException;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+/**
+ * This test class for the covering the unit tests for constraint
+ * {@link io.ballerina.openapi.converter.service.ConstraintAnnotation} scenarios.
+ *
+ */
+public class ConstraintTests {
+    private static final Path RES_DIR = Paths.get("src/test/resources/ballerina-to-openapi").toAbsolutePath();
+
+    @Test(description = "When the record field has constraint type")
+    public void testMapFiled() throws IOException {
+        Path ballerinaFilePath = RES_DIR.resolve("constraint/record_field.bal");
+        TestUtils.compareWithGeneratedFile(ballerinaFilePath, "constraint/record_field.yaml");
+    }
+
+    @Test(description = "When the record field has constraint type with records")
+    public void testMapRecFiled() throws IOException {
+        Path ballerinaFilePath = RES_DIR.resolve("constraint/record_fieldRec.bal");
+        TestUtils.compareWithGeneratedFile(ballerinaFilePath, "constraint/record_fieldRec.yaml");
+    }
+
+    @Test(description = "When the record field has array type")
+    public void testArrayType() throws IOException {
+        Path ballerinaFilePath = RES_DIR.resolve("constraint/array.bal");
+        TestUtils.compareWithGeneratedFile(ballerinaFilePath, "constraint/array.yaml");
+    }
+
+    @Test(description = "When the record field has array record type")
+    public void testArrayRecType() throws IOException {
+        Path ballerinaFilePath = RES_DIR.resolve("constraint/arrayRec.bal");
+        TestUtils.compareWithGeneratedFile(ballerinaFilePath, "constraint/arrayRec.yaml");
+    }
+
+    @Test(description = "When the record field has integer (minValueExclusive) type")
+    public void testIntegerMinType() throws IOException {
+        Path ballerinaFilePath = RES_DIR.resolve("constraint/integerMin.bal");
+        TestUtils.compareWithGeneratedFile(ballerinaFilePath, "constraint/integerMin.yaml");
+    }
+
+    @Test(description = "When the record field has integer (maxValueExclusive) type")
+    public void testIntegerMaxType() throws IOException {
+        Path ballerinaFilePath = RES_DIR.resolve("constraint/integerMax.bal");
+        TestUtils.compareWithGeneratedFile(ballerinaFilePath, "constraint/integerMax.yaml");
+    }
+
+    @Test(description = "When the record field has integer record type")
+    public void testIntegerRecType() throws IOException {
+        Path ballerinaFilePath = RES_DIR.resolve("constraint/integerRec.bal");
+        TestUtils.compareWithGeneratedFile(ballerinaFilePath, "constraint/integerRec.yaml");
+    }
+
+    @Test(description = "When the record field has float (minValueExclusive) type")
+    public void testFloatMinType() throws IOException {
+        Path ballerinaFilePath = RES_DIR.resolve("constraint/floatMin.bal");
+        TestUtils.compareWithGeneratedFile(ballerinaFilePath, "constraint/floatMin.yaml");
+    }
+
+    @Test(description = "When the record field has float (maxValueExclusive) type")
+    public void testFloatMaxType() throws IOException {
+        Path ballerinaFilePath = RES_DIR.resolve("constraint/floatMax.bal");
+        TestUtils.compareWithGeneratedFile(ballerinaFilePath, "constraint/floatMax.yaml");
+    }
+
+    @Test(description = "When the record field has float record type")
+    public void testFloatRecType() throws IOException {
+        Path ballerinaFilePath = RES_DIR.resolve("constraint/floatRec.bal");
+        TestUtils.compareWithGeneratedFile(ballerinaFilePath, "constraint/floatRec.yaml");
+    }
+
+    @Test(description = "When the record field has decimal (minValueExclusive) type")
+    public void testDecimalMinType() throws IOException {
+        Path ballerinaFilePath = RES_DIR.resolve("constraint/decimalMin.bal");
+        TestUtils.compareWithGeneratedFile(ballerinaFilePath, "constraint/decimalMin.yaml");
+    }
+
+    @Test(description = "When the record field has decimal (maxValueExclusive) type")
+    public void testDecimalMaxType() throws IOException {
+        Path ballerinaFilePath = RES_DIR.resolve("constraint/decimalMax.bal");
+        TestUtils.compareWithGeneratedFile(ballerinaFilePath, "constraint/decimalMax.yaml");
+    }
+
+    @Test(description = "When the record field has decimal record type")
+    public void testDecimalRecType() throws IOException {
+        Path ballerinaFilePath = RES_DIR.resolve("constraint/decimalRec.bal");
+        TestUtils.compareWithGeneratedFile(ballerinaFilePath, "constraint/decimalRec.yaml");
+    }
+
+    @Test(description = "When the record field has string type")
+    public void testStringType() throws IOException {
+        Path ballerinaFilePath = RES_DIR.resolve("constraint/string.bal");
+        TestUtils.compareWithGeneratedFile(ballerinaFilePath, "constraint/string.yaml");
+    }
+
+    @Test(description = "When the record field has string record type")
+    public void testStringRecType() throws IOException {
+        Path ballerinaFilePath = RES_DIR.resolve("constraint/stringRec.bal");
+        TestUtils.compareWithGeneratedFile(ballerinaFilePath, "constraint/stringRec.yaml");
+    }
+}
diff --git a/openapi-cli/src/test/java/io/ballerina/openapi/generators/openapi/ModuleReferenceTests.java b/openapi-cli/src/test/java/io/ballerina/openapi/generators/openapi/ModuleReferenceTests.java
index ede75ddcc..a7245fc91 100644
--- a/openapi-cli/src/test/java/io/ballerina/openapi/generators/openapi/ModuleReferenceTests.java
+++ b/openapi-cli/src/test/java/io/ballerina/openapi/generators/openapi/ModuleReferenceTests.java
@@ -73,6 +73,7 @@ public void testRecordReferenceWithReadOnly() throws IOException {
         TestUtils.compareWithGeneratedFile(ballerinaFilePath, "readonly.yaml");
     }
 
+    //To-Do: This test is disabled due to an Ubuntu build failure.
     @Test (enabled = false)
     public void testListenersInSeparateModule() throws IOException {
         Path ballerinaFilePath = RES_DIR.resolve("listeners_in_separate_module.bal");
@@ -82,6 +83,7 @@ public void testListenersInSeparateModule() throws IOException {
         TestUtils.compareWithGeneratedFile(ballerinaFilePath, yamlFile);
     }
 
+    //To-Do: This test is disabled due to an Ubuntu build failure.
     @Test (enabled = false)
     public void testListenersInSeparateFiles() throws IOException {
         Path ballerinaFilePath = RES_DIR.resolve("listeners_in_separate_file.bal");
diff --git a/openapi-cli/src/test/java/io/ballerina/openapi/generators/openapi/NegativeConstraintTests.java b/openapi-cli/src/test/java/io/ballerina/openapi/generators/openapi/NegativeConstraintTests.java
new file mode 100644
index 000000000..7c98436ed
--- /dev/null
+++ b/openapi-cli/src/test/java/io/ballerina/openapi/generators/openapi/NegativeConstraintTests.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com).
+ *
+ * WSO2 LLC. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package io.ballerina.openapi.generators.openapi;
+
+import io.ballerina.openapi.cmd.OASContractGenerator;
+import io.ballerina.openapi.converter.diagnostic.OpenAPIConverterDiagnostic;
+import io.ballerina.projects.DiagnosticResult;
+import io.ballerina.projects.Project;
+import io.ballerina.projects.ProjectException;
+import io.ballerina.projects.directory.ProjectLoader;
+import io.ballerina.tools.diagnostics.DiagnosticSeverity;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import java.io.IOException;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Arrays;
+import java.util.List;
+
+import static io.ballerina.openapi.generators.openapi.TestUtils.getCompilation;
+
+/**
+ * This test class for the covering the negative tests for constraint
+ * {@link io.ballerina.openapi.converter.service.ConstraintAnnotation} scenarios.
+ *
+ */
+public class NegativeConstraintTests {
+    private static final Path RES_DIR = Paths.get("src/test/resources/ballerina-to-openapi").toAbsolutePath();
+
+    @Test(description = "When the string constraint has incompatible REGEX patterns with OAS")
+    public void testInterpolationInRegexPatterns() throws IOException {
+        Path ballerinaFilePath = RES_DIR.resolve("constraint-negative/negative_patternInterpolation.bal");
+        List errors = TestUtils.compareWithGeneratedFile(new OASContractGenerator(),
+                                    ballerinaFilePath, "constraint-negative/negative_patternInterpolation.yaml");
+        List expectedPatterns = Arrays.asList("^${i}[a-zA-Z]+$", "^[A-Z]${j}+$", "^[\\${2}a-z]+$"
+                                                     , "^[a-z${2}]+$");
+        for (int i = 0; i < errors.size(); i++) {
+            Assert.assertEquals(errors.get(i).getMessage(), "Given REGEX pattern '" + expectedPatterns.get(i) +
+                    "' is not supported by the OpenAPI tool, it may also not support interpolation within the " +
+                    "REGEX pattern.");
+        }
+    }
+
+    @Test(description = "When a constraint has values referenced with variables")
+    public void testConstNameRef() throws IOException {
+        Path ballerinaFilePath = RES_DIR.resolve("constraint-negative/negative_constNameRef.bal");
+        List errors = TestUtils.compareWithGeneratedFile(new OASContractGenerator(),
+                ballerinaFilePath, "constraint-negative/negative_constNameRef.yaml");
+        List expectedVariables = Arrays.asList("maxVal", "5 + minVal", "Value");
+        for (int i = 0; i < errors.size(); i++) {
+            Assert.assertEquals(errors.get(i).getMessage(), "Generated OpenAPI definition does not contain" +
+                    " variable assignment '" + expectedVariables.get(i) + "' in constraint validation.");
+        }
+    }
+
+    /*
+     * This test is used to check whether it gives warnings when '@constraint:Date' is being used.
+     * Currently, we don't have support for mapping Date constraints to OAS hence we skip them.
+     * TODO: ...
+     * Once the above improvement is completed this Negative test should be removed and should add as a Unit test!
+     */
+    @Test(description = "when the record field has time:Date record type")
+    public void testDateType() throws IOException {
+        Path ballerinaFilePath = RES_DIR.resolve("constraint-negative/negative_date.bal");
+        List errors = TestUtils.compareWithGeneratedFile(new OASContractGenerator(),
+                ballerinaFilePath, "constraint-negative/negative_date.yaml");
+        errors.forEach(error -> Assert.assertEquals(error.getMessage(), "Ballerina Date constraints might " +
+                "not be reflected in the OpenAPI definition"));
+    }
+
+    /*
+     * This test is used to check whether it gives compilation errors when invalid REGEX patterns are given.
+     * To get more context go through the referenced links.
+     * By fixing below Bug will make this test fail.
+     * {@link ...}
+     * TODO: ...
+     */
+    @Test(description = "When String constraint has compilation errors (REGEX pattern with invalid format)")
+    public void testInvalidRegexPattern() throws ProjectException {
+        Path ballerinaFilePath = RES_DIR.resolve("constraint-negative/invalidRegexPattern.bal");
+        Project project = ProjectLoader.loadProject(ballerinaFilePath);
+        DiagnosticResult diagnostic = getCompilation(project);
+        Object[] errors = diagnostic.diagnostics().stream().filter(d ->
+                DiagnosticSeverity.ERROR == d.diagnosticInfo().severity()).toArray();
+        Assert.assertEquals(errors.length, 2);
+        Assert.assertTrue(errors[0].toString().contains("ERROR [invalidRegexPattern.bal:(21:20,21:20)] " +
+                "invalid char after backslash"));
+        Assert.assertTrue(errors[1].toString().contains("ERROR [invalidRegexPattern.bal:(21:22,21:22)] " +
+                "missing backslash"));
+    }
+
+    @Test(description = "When Integer constraint has float value which is invalid")
+    public void testInvalidInteger() throws ProjectException {
+        Path ballerinaFilePath = RES_DIR.resolve("constraint-negative/invalidInteger.bal");
+        Project project = ProjectLoader.loadProject(ballerinaFilePath);
+        DiagnosticResult diagnostic = getCompilation(project);
+        Object[] errors = diagnostic.diagnostics().stream().filter(d ->
+                DiagnosticSeverity.ERROR == d.diagnosticInfo().severity()).toArray();
+        Assert.assertEquals(errors.length, 1);
+        Assert.assertTrue(errors[0].toString().contains("incompatible types: expected '(int|record {| int value; " +
+                "string message; |})?', found 'float'"));
+    }
+}
diff --git a/openapi-cli/src/test/java/io/ballerina/openapi/generators/openapi/TestUtils.java b/openapi-cli/src/test/java/io/ballerina/openapi/generators/openapi/TestUtils.java
index 50ce2b4c6..c24de2e45 100644
--- a/openapi-cli/src/test/java/io/ballerina/openapi/generators/openapi/TestUtils.java
+++ b/openapi-cli/src/test/java/io/ballerina/openapi/generators/openapi/TestUtils.java
@@ -18,6 +18,10 @@
 package io.ballerina.openapi.generators.openapi;
 
 import io.ballerina.openapi.cmd.OASContractGenerator;
+import io.ballerina.openapi.converter.diagnostic.OpenAPIConverterDiagnostic;
+import io.ballerina.projects.DiagnosticResult;
+import io.ballerina.projects.Package;
+import io.ballerina.projects.Project;
 import org.testng.Assert;
 
 import java.io.File;
@@ -26,6 +30,7 @@
 import java.nio.file.Path;
 import java.nio.file.Paths;
 import java.util.Comparator;
+import java.util.List;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
@@ -52,11 +57,17 @@ public static void deleteGeneratedFiles(String filename, Path tempDir) {
     }
 
     public static void compareWithGeneratedFile(Path ballerinaFilePath, String yamlFile) throws IOException {
+        compareWithGeneratedFile(new OASContractGenerator(), ballerinaFilePath, yamlFile);
+    }
+
+    public static List compareWithGeneratedFile(OASContractGenerator openApiConverter,
+                                                                            Path ballerinaFilePath, String yamlFile)
+                                                                            throws IOException {
         Path tempDir = Files.createTempDirectory("bal-to-openapi-test-out-" + System.nanoTime());
         try {
             String expectedYamlContent = getStringFromGivenBalFile(RES_DIR.resolve("expected_gen"), yamlFile);
-            OASContractGenerator openApiConverter = new OASContractGenerator();
-            openApiConverter.generateOAS3DefinitionsAllService(ballerinaFilePath, tempDir, null, false);
+            openApiConverter.generateOAS3DefinitionsAllService(
+                    ballerinaFilePath, tempDir, null, false);
             if (Files.exists(tempDir.resolve("payloadV_openapi.yaml"))) {
                 String generatedYaml = getStringFromGivenBalFile(tempDir, "payloadV_openapi.yaml");
                 generatedYaml = (generatedYaml.trim()).replaceAll("\\s+", "");
@@ -65,8 +76,10 @@ public static void compareWithGeneratedFile(Path ballerinaFilePath, String yamlF
             } else {
                 Assert.fail("Yaml was not generated");
             }
+            return openApiConverter.getErrors();
         } catch (IOException e) {
             Assert.fail("Error while generating the service. " + e.getMessage());
+            return List.of();
         } finally {
             deleteGeneratedFiles("payloadV_openapi.yaml", tempDir);
             deleteDirectory(tempDir);
@@ -74,6 +87,11 @@ public static void compareWithGeneratedFile(Path ballerinaFilePath, String yamlF
         }
     }
 
+    public static DiagnosticResult getCompilation(Project project) {
+        Package cPackage = project.currentPackage();
+        return  cPackage.getCompilation().diagnosticResult();
+    }
+
     public static void deleteDirectory(Path path) {
         if (!Files.exists(path)) {
             return;
diff --git a/openapi-cli/src/test/resources/ballerina-to-openapi/ballerina-project/service/modules/types/types.bal b/openapi-cli/src/test/resources/ballerina-to-openapi/ballerina-project/service/modules/types/types.bal
index 4b47d1088..ae2012381 100644
--- a/openapi-cli/src/test/resources/ballerina-to-openapi/ballerina-project/service/modules/types/types.bal
+++ b/openapi-cli/src/test/resources/ballerina-to-openapi/ballerina-project/service/modules/types/types.bal
@@ -1,4 +1,6 @@
 import ballerina/http;
+import ballerina/constraint;
+
 # Represents a product
 #
 # + name - Name of the product
@@ -6,6 +8,7 @@ import ballerina/http;
 # + price - Product price
 public type Product record {|
     string id?;
+    @constraint:String {maxLength: 14}
     string name;
     string description;
     Price price;
diff --git a/openapi-cli/src/test/resources/ballerina-to-openapi/constraint-negative/invalidInteger.bal b/openapi-cli/src/test/resources/ballerina-to-openapi/constraint-negative/invalidInteger.bal
new file mode 100644
index 000000000..ee416c64c
--- /dev/null
+++ b/openapi-cli/src/test/resources/ballerina-to-openapi/constraint-negative/invalidInteger.bal
@@ -0,0 +1,33 @@
+// Copyright (c) 2023, WSO2 LLC. (http://www.wso2.org).
+//
+// WSO2 LLC. licenses this file to you under the Apache License,
+// Version 2.0 (the "License"); you may not use this file except
+// in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+import ballerina/http;
+import ballerina/constraint;
+
+@constraint:Int{
+    minValueExclusive: 10.5
+}
+public type Distance int;
+
+public type City record{
+    Distance distance;
+};
+
+service /payloadV on new http:Listener(9090) {
+    resource function post pet(@http:Payload City body) returns error? {
+        return;
+    }
+}
diff --git a/openapi-cli/src/test/resources/ballerina-to-openapi/constraint-negative/invalidRegexPattern.bal b/openapi-cli/src/test/resources/ballerina-to-openapi/constraint-negative/invalidRegexPattern.bal
new file mode 100644
index 000000000..0653cc38b
--- /dev/null
+++ b/openapi-cli/src/test/resources/ballerina-to-openapi/constraint-negative/invalidRegexPattern.bal
@@ -0,0 +1,33 @@
+// Copyright (c) 2023, WSO2 LLC. (http://www.wso2.org).
+//
+// WSO2 LLC. licenses this file to you under the Apache License,
+// Version 2.0 (the "License"); you may not use this file except
+// in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+import ballerina/http;
+import ballerina/constraint;
+
+@constraint:String {
+    pattern: re `^\${1,2}[a-z]+$`
+}
+public type Position string;
+
+public type Child record {
+    Position position;
+};
+
+service /payloadV on new http:Listener(9090) {
+    resource function post pet(@http:Payload Child body) returns error? {
+        return;
+    }
+}
diff --git a/openapi-cli/src/test/resources/ballerina-to-openapi/constraint-negative/negative_constNameRef.bal b/openapi-cli/src/test/resources/ballerina-to-openapi/constraint-negative/negative_constNameRef.bal
new file mode 100644
index 000000000..c04f396eb
--- /dev/null
+++ b/openapi-cli/src/test/resources/ballerina-to-openapi/constraint-negative/negative_constNameRef.bal
@@ -0,0 +1,42 @@
+// Copyright (c) 2023, WSO2 LLC. (http://www.wso2.org).
+//
+// WSO2 LLC. licenses this file to you under the Apache License,
+// Version 2.0 (the "License"); you may not use this file except
+// in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+import ballerina/http;
+import ballerina/constraint;
+
+int maxVal = 100;
+int minVal = 5;
+const float Value = 10.5;
+@constraint:Int {
+    maxValueExclusive: maxVal,
+    minValue: {
+        value: 5 + minVal,
+        message: "Min value exceeded!"
+    }
+}
+public type St_ID int;
+
+public type StudentRecord record {
+    St_ID id;
+    @constraint:Float { minValue: Value}
+    float num?;
+};
+
+service /payloadV on new http:Listener(9090) {
+    resource function post pet(@http:Payload StudentRecord body) returns error? {
+        return;
+    }
+}
diff --git a/openapi-cli/src/test/resources/ballerina-to-openapi/constraint-negative/negative_date.bal b/openapi-cli/src/test/resources/ballerina-to-openapi/constraint-negative/negative_date.bal
new file mode 100644
index 000000000..41dc5a6c8
--- /dev/null
+++ b/openapi-cli/src/test/resources/ballerina-to-openapi/constraint-negative/negative_date.bal
@@ -0,0 +1,43 @@
+// Copyright (c) 2023, WSO2 LLC. (http://www.wso2.org).
+//
+// WSO2 LLC. licenses this file to you under the Apache License,
+// Version 2.0 (the "License"); you may not use this file except
+// in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+import ballerina/http;
+import ballerina/constraint;
+import ballerina/time;
+
+@constraint:Date {
+    option: constraint:FUTURE,
+    message: "Event date cannot be past!"
+}
+public type MyDate time:Date;
+
+type RegDate record {
+    MyDate date;
+    @constraint:Date {
+        option: {
+            value: constraint:PAST,
+            message: "Last login should be past!"
+        },
+        message: "Invalid date found for last login!"
+    }
+    time:Date lastLogin?;
+};
+
+service /payloadV on new http:Listener(9090) {
+    resource function post pet(RegDate body) returns error? {
+	    return;
+    }
+}
diff --git a/openapi-cli/src/test/resources/ballerina-to-openapi/constraint-negative/negative_patternInterpolation.bal b/openapi-cli/src/test/resources/ballerina-to-openapi/constraint-negative/negative_patternInterpolation.bal
new file mode 100644
index 000000000..31fae177a
--- /dev/null
+++ b/openapi-cli/src/test/resources/ballerina-to-openapi/constraint-negative/negative_patternInterpolation.bal
@@ -0,0 +1,50 @@
+// Copyright (c) 2023, WSO2 LLC. (http://www.wso2.org).
+//
+// WSO2 LLC. licenses this file to you under the Apache License,
+// Version 2.0 (the "License"); you may not use this file except
+// in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+import ballerina/http;
+import ballerina/constraint;
+
+int i = 123;
+int j = 20;
+@constraint:String {
+    length: 21,
+    pattern: re `^${i}[a-zA-Z]+$`
+}
+public type PosID string;
+
+@constraint:String {
+    pattern: re `^[\${2}a-z]+$`
+}
+public type EmpID string;
+
+@constraint:String {
+    pattern: re `^[a-z${2}]+$`
+}
+public type Name string;
+
+public type Emp record {
+    PosID posId;
+    @constraint:String { pattern: re `^[A-Z]${j}+$`}
+    string code?;
+    EmpID empID?;
+    Name name?;
+};
+
+service /payloadV on new http:Listener(9090) {
+    resource function post pet(@http:Payload Emp body) returns error? {
+        return;
+    }
+}
diff --git a/openapi-cli/src/test/resources/ballerina-to-openapi/constraint/array.bal b/openapi-cli/src/test/resources/ballerina-to-openapi/constraint/array.bal
new file mode 100644
index 000000000..d15387730
--- /dev/null
+++ b/openapi-cli/src/test/resources/ballerina-to-openapi/constraint/array.bal
@@ -0,0 +1,40 @@
+import ballerina/http;
+import ballerina/constraint;
+
+@constraint:String {maxLength: 23}
+public type HobbyItemsString string;
+
+@constraint:String {minLength: 7}
+public type PersonDetailsItemsString string;
+
+@constraint:String {minLength: 5}
+public type SchoolName string;
+
+@constraint:Float {maxValue: 445.4}
+public type PersonFeeItemsNumber float;
+
+@constraint:Int {maxValue: 67 }
+public type PersonLimitItemsInteger int;
+
+@constraint:Array {maxLength: 5, minLength: 2}
+public type Hobby HobbyItemsString[];
+
+@constraint:Array {length: 15}
+public type School SchoolName[];
+
+public type Person record {
+    Hobby hobby?;
+    School school?;
+    @constraint:Array {maxLength: 5}
+    PersonDetailsItemsString[] Details?;
+    int id;
+    PersonFeeItemsNumber[] fee?;
+    # The maximum number of items in the response (as set in the query or by default).
+    PersonLimitItemsInteger[] 'limit?;
+};
+
+service /payloadV on new http:Listener(9090) {
+    resource function post pet(@http:Payload Person body) returns error? {
+        return;
+    }
+}
diff --git a/openapi-cli/src/test/resources/ballerina-to-openapi/constraint/arrayRec.bal b/openapi-cli/src/test/resources/ballerina-to-openapi/constraint/arrayRec.bal
new file mode 100644
index 000000000..83bd91e28
--- /dev/null
+++ b/openapi-cli/src/test/resources/ballerina-to-openapi/constraint/arrayRec.bal
@@ -0,0 +1,49 @@
+// Copyright (c) 2023, WSO2 LLC. (http://www.wso2.org).
+//
+// WSO2 LLC. licenses this file to you under the Apache License,
+// Version 2.0 (the "License"); you may not use this file except
+// in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+import ballerina/http;
+import ballerina/constraint;
+
+@constraint:String {maxLength: 23}
+public type HobbyItemsString string;
+
+@constraint:String {minLength: 7}
+public type PersonDetailsItemsString string;
+
+@constraint:Float {maxValue: 445.4}
+public type PersonFeeItemsNumber float;
+
+@constraint:Int {maxValue: 67 }
+public type PersonLimitItemsInteger int;
+
+@constraint:Array {maxLength: 5, minLength: { value: 2, message: "Min Length Exceeded!"}}
+public type Hobby HobbyItemsString[];
+
+public type Person record {
+    Hobby hobby?;
+    @constraint:Array {maxLength: 5}
+    PersonDetailsItemsString[] Details?;
+    int id;
+    PersonFeeItemsNumber[] fee?;
+    # The maximum number of items in the response (as set in the query or by default).
+    PersonLimitItemsInteger[] 'limit?;
+};
+
+service /payloadV on new http:Listener(9090) {
+    resource function post pet(@http:Payload Person body) returns error? {
+        return;
+    }
+}
diff --git a/openapi-cli/src/test/resources/ballerina-to-openapi/constraint/decimalMax.bal b/openapi-cli/src/test/resources/ballerina-to-openapi/constraint/decimalMax.bal
new file mode 100644
index 000000000..99b02f9e7
--- /dev/null
+++ b/openapi-cli/src/test/resources/ballerina-to-openapi/constraint/decimalMax.bal
@@ -0,0 +1,34 @@
+// Copyright (c) 2023, WSO2 LLC. (http://www.wso2.org).
+//
+// WSO2 LLC. licenses this file to you under the Apache License,
+// Version 2.0 (the "License"); you may not use this file except
+// in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+import ballerina/http;
+import ballerina/constraint;
+
+@constraint:Number {
+    maxValueExclusive: 5.55,
+    minValue: 2.55
+}
+public type Marks decimal;
+
+public type School record {
+    Marks marks;
+};
+
+service /payloadV on new http:Listener(9090) {
+    resource function post pet(@http:Payload School body) returns error? {
+        return;
+    }
+}
diff --git a/openapi-cli/src/test/resources/ballerina-to-openapi/constraint/decimalMin.bal b/openapi-cli/src/test/resources/ballerina-to-openapi/constraint/decimalMin.bal
new file mode 100644
index 000000000..09d6e5d1c
--- /dev/null
+++ b/openapi-cli/src/test/resources/ballerina-to-openapi/constraint/decimalMin.bal
@@ -0,0 +1,34 @@
+// Copyright (c) 2023, WSO2 LLC. (http://www.wso2.org).
+//
+// WSO2 LLC. licenses this file to you under the Apache License,
+// Version 2.0 (the "License"); you may not use this file except
+// in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+import ballerina/http;
+import ballerina/constraint;
+
+@constraint:Number {
+    minValueExclusive: 2.55,
+    maxValue: 5.55
+}
+public type Marks decimal;
+
+public type School record {
+    Marks marks;
+};
+
+service /payloadV on new http:Listener(9090) {
+    resource function post pet(@http:Payload School body) returns error? {
+        return;
+    }
+}
diff --git a/openapi-cli/src/test/resources/ballerina-to-openapi/constraint/decimalRec.bal b/openapi-cli/src/test/resources/ballerina-to-openapi/constraint/decimalRec.bal
new file mode 100644
index 000000000..10d4ee4f7
--- /dev/null
+++ b/openapi-cli/src/test/resources/ballerina-to-openapi/constraint/decimalRec.bal
@@ -0,0 +1,37 @@
+// Copyright (c) 2023, WSO2 LLC. (http://www.wso2.org). 
+//
+// WSO2 LLC. licenses this file to you under the Apache License,
+// Version 2.0 (the "License"); you may not use this file except
+// in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+import ballerina/http;
+import ballerina/constraint;
+
+@constraint:Number {
+    minValueExclusive: {
+        value: 2.55,
+        message: "Min Value Exceeded!"
+    },
+    maxValue: 5.55
+}
+public type Marks decimal;
+
+public type School record {
+    Marks marks;
+};
+
+service /payloadV on new http:Listener(9090) {
+    resource function post pet(@http:Payload School body) returns error? {
+        return;
+    }
+}
diff --git a/openapi-cli/src/test/resources/ballerina-to-openapi/constraint/floatMax.bal b/openapi-cli/src/test/resources/ballerina-to-openapi/constraint/floatMax.bal
new file mode 100644
index 000000000..da3d30f8c
--- /dev/null
+++ b/openapi-cli/src/test/resources/ballerina-to-openapi/constraint/floatMax.bal
@@ -0,0 +1,34 @@
+// Copyright (c) 2023, WSO2 LLC. (http://www.wso2.org).
+//
+// WSO2 LLC. licenses this file to you under the Apache License,
+// Version 2.0 (the "License"); you may not use this file except
+// in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+import ballerina/http;
+import ballerina/constraint;
+
+@constraint:Float {
+    maxValueExclusive: 10.5,
+    minValue: 2.5
+}
+public type Rating float;
+
+public type Hotel record {
+    Rating rate;
+};
+
+service /payloadV on new http:Listener(9090) {
+    resource function post pet(@http:Payload Hotel body) returns error? {
+        return;
+    }
+}
diff --git a/openapi-cli/src/test/resources/ballerina-to-openapi/constraint/floatMin.bal b/openapi-cli/src/test/resources/ballerina-to-openapi/constraint/floatMin.bal
new file mode 100644
index 000000000..b143121ef
--- /dev/null
+++ b/openapi-cli/src/test/resources/ballerina-to-openapi/constraint/floatMin.bal
@@ -0,0 +1,34 @@
+// Copyright (c) 2023, WSO2 LLC. (http://www.wso2.org).
+//
+// WSO2 LLC. licenses this file to you under the Apache License,
+// Version 2.0 (the "License"); you may not use this file except
+// in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+import ballerina/http;
+import ballerina/constraint;
+
+@constraint:Float {
+    minValueExclusive: 2.5,
+    maxValue: 10.5
+}
+public type Rating float;
+
+public type Hotel record {
+    Rating rate;
+};
+
+service /payloadV on new http:Listener(9090) {
+    resource function post pet(@http:Payload Hotel body) returns error? {
+        return;
+    }
+}
diff --git a/openapi-cli/src/test/resources/ballerina-to-openapi/constraint/floatRec.bal b/openapi-cli/src/test/resources/ballerina-to-openapi/constraint/floatRec.bal
new file mode 100644
index 000000000..27d1519cf
--- /dev/null
+++ b/openapi-cli/src/test/resources/ballerina-to-openapi/constraint/floatRec.bal
@@ -0,0 +1,37 @@
+// Copyright (c) 2023, WSO2 LLC. (http://www.wso2.org). 
+//
+// WSO2 LLC. licenses this file to you under the Apache License,
+// Version 2.0 (the "License"); you may not use this file except
+// in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+import ballerina/http;
+import ballerina/constraint;
+
+@constraint:Float {
+    maxValueExclusive: {
+        value: 10.5,
+        message: "Max Value Exceeded!"
+    },
+    minValue: 2.5
+}
+public type Rating float;
+
+public type Hotel record {
+    Rating rate;
+};
+
+service /payloadV on new http:Listener(9090) {
+    resource function post pet(@http:Payload Hotel body) returns error? {
+        return;
+    }
+}
diff --git a/openapi-cli/src/test/resources/ballerina-to-openapi/constraint/integerMax.bal b/openapi-cli/src/test/resources/ballerina-to-openapi/constraint/integerMax.bal
new file mode 100644
index 000000000..e71ccfc49
--- /dev/null
+++ b/openapi-cli/src/test/resources/ballerina-to-openapi/constraint/integerMax.bal
@@ -0,0 +1,34 @@
+// Copyright (c) 2023, WSO2 LLC. (http://www.wso2.org).
+//
+// WSO2 LLC. licenses this file to you under the Apache License,
+// Version 2.0 (the "License"); you may not use this file except
+// in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+import ballerina/http;
+import ballerina/constraint;
+
+@constraint:Int{
+    maxValueExclusive: 100,
+    minValue: 10
+}
+public type Position int;
+
+public type Child record {
+    Position position;
+};
+
+service /payloadV on new http:Listener(9090) {
+    resource function post pet(@http:Payload Child body) returns error? {
+        return;
+    }
+}
diff --git a/openapi-cli/src/test/resources/ballerina-to-openapi/constraint/integerMin.bal b/openapi-cli/src/test/resources/ballerina-to-openapi/constraint/integerMin.bal
new file mode 100644
index 000000000..1442c0162
--- /dev/null
+++ b/openapi-cli/src/test/resources/ballerina-to-openapi/constraint/integerMin.bal
@@ -0,0 +1,34 @@
+// Copyright (c) 2023, WSO2 LLC. (http://www.wso2.org).
+//
+// WSO2 LLC. licenses this file to you under the Apache License,
+// Version 2.0 (the "License"); you may not use this file except
+// in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+import ballerina/http;
+import ballerina/constraint;
+
+@constraint:Int{
+    minValueExclusive: 0,
+    maxValue: 50
+}
+public type Position int;
+
+public type Child record {
+    Position position;
+};
+
+service /payloadV on new http:Listener(9090) {
+    resource function post pet(@http:Payload Child body) returns error? {
+        return;
+    }
+}
diff --git a/openapi-cli/src/test/resources/ballerina-to-openapi/constraint/integerRec.bal b/openapi-cli/src/test/resources/ballerina-to-openapi/constraint/integerRec.bal
new file mode 100644
index 000000000..7e691bf23
--- /dev/null
+++ b/openapi-cli/src/test/resources/ballerina-to-openapi/constraint/integerRec.bal
@@ -0,0 +1,37 @@
+// Copyright (c) 2023, WSO2 LLC. (http://www.wso2.org).
+//
+// WSO2 LLC. licenses this file to you under the Apache License,
+// Version 2.0 (the "License"); you may not use this file except
+// in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+import ballerina/http;
+import ballerina/constraint;
+
+@constraint:Int{
+    minValueExclusive: 0,
+    maxValue: {
+        value: 50,
+        message: "Max Value Exceeded!"
+    }
+}
+public type Position int;
+
+public type Child record {
+    Position position;
+};
+
+service /payloadV on new http:Listener(9090) {
+    resource function post pet(@http:Payload Child body) returns error? {
+        return;
+    }
+}
diff --git a/openapi-cli/src/test/resources/ballerina-to-openapi/constraint/record_field.bal b/openapi-cli/src/test/resources/ballerina-to-openapi/constraint/record_field.bal
new file mode 100644
index 000000000..cc34bf2aa
--- /dev/null
+++ b/openapi-cli/src/test/resources/ballerina-to-openapi/constraint/record_field.bal
@@ -0,0 +1,25 @@
+import ballerina/http;
+import ballerina/constraint;
+
+@constraint:String {minLength: 5}
+public type Address string;
+
+public type Person record {
+    @constraint:String {maxLength: 14}
+    string name?;
+    @constraint:Array {maxLength: 5, minLength: 2}
+    string[] hobby?;
+    @constraint:Int {maxValueExclusive: 5, minValue: 0}
+    int id;
+    Address address?;
+    @constraint:Float {maxValueExclusive: 100000, minValue: 1000}
+    float salary?;
+    @constraint:Number {minValueExclusive: 500000, maxValue: 1000000}
+    decimal net?;
+};
+
+service /payloadV on new http:Listener(9090) {
+    resource function post pet(@http:Payload Person body) returns error? {
+        return;
+    }
+}
\ No newline at end of file
diff --git a/openapi-cli/src/test/resources/ballerina-to-openapi/constraint/record_fieldRec.bal b/openapi-cli/src/test/resources/ballerina-to-openapi/constraint/record_fieldRec.bal
new file mode 100644
index 000000000..d1513b629
--- /dev/null
+++ b/openapi-cli/src/test/resources/ballerina-to-openapi/constraint/record_fieldRec.bal
@@ -0,0 +1,70 @@
+// Copyright (c) 2023, WSO2 LLC. (http://www.wso2.org).
+//
+// WSO2 LLC. licenses this file to you under the Apache License,
+// Version 2.0 (the "License"); you may not use this file except
+// in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+import ballerina/http;
+import ballerina/constraint;
+
+@constraint:String {minLength: 5}
+public type Address string;
+
+public type Person record {
+    @constraint:String {
+        maxLength: {
+            value: 14,
+            message: "Max Length Exceeded!"
+        }
+    }
+    string name?;
+    @constraint:Array {
+        maxLength: 5,
+        minLength: {
+            value: 2,
+            message: "Min Length Exceeded!"
+        }
+    }
+    string[] hobby?;
+    @constraint:Int {
+        maxValueExclusive: {
+            value: 5,
+            message: "Max Value Exceeded!"
+        },
+        minValue: 0
+    }
+    int id;
+    Address address?;
+    @constraint:Float {
+        maxValueExclusive: {
+            value: 100000,
+            message: "Min Value Exceeded!"
+        },
+        minValue: 1000
+    }
+    float salary?;
+    @constraint:Number {
+        minValueExclusive: 500000,
+        maxValue: {
+            value: 1000000,
+            message: "Max Value Exceeded!"
+        }
+    }
+    decimal net?;
+};
+
+service /payloadV on new http:Listener(9090) {
+    resource function post pet(@http:Payload Person body) returns error? {
+        return;
+    }
+}
diff --git a/openapi-cli/src/test/resources/ballerina-to-openapi/constraint/string.bal b/openapi-cli/src/test/resources/ballerina-to-openapi/constraint/string.bal
new file mode 100644
index 000000000..8a1d793c7
--- /dev/null
+++ b/openapi-cli/src/test/resources/ballerina-to-openapi/constraint/string.bal
@@ -0,0 +1,36 @@
+// Copyright (c) 2023, WSO2 LLC. (http://www.wso2.org).
+//
+// WSO2 LLC. licenses this file to you under the Apache License,
+// Version 2.0 (the "License"); you may not use this file except
+// in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+import ballerina/http;
+import ballerina/constraint;
+
+@constraint:String {
+    length: 10,
+    pattern: re `^[a-zA-Z0-9_]+$`
+}
+public type St_ID string;
+
+public type StudentRecord record {
+    St_ID id;
+    @constraint:String { pattern: re `^[a-zA-Z]+$`}
+    string name?;
+};
+
+service /payloadV on new http:Listener(9090) {
+    resource function post pet(@http:Payload StudentRecord body) returns error? {
+        return;
+    }
+}
diff --git a/openapi-cli/src/test/resources/ballerina-to-openapi/constraint/stringRec.bal b/openapi-cli/src/test/resources/ballerina-to-openapi/constraint/stringRec.bal
new file mode 100644
index 000000000..1f9b74cab
--- /dev/null
+++ b/openapi-cli/src/test/resources/ballerina-to-openapi/constraint/stringRec.bal
@@ -0,0 +1,42 @@
+// Copyright (c) 2023, WSO2 LLC. (http://www.wso2.org).
+//
+// WSO2 LLC. licenses this file to you under the Apache License,
+// Version 2.0 (the "License"); you may not use this file except
+// in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+import ballerina/http;
+import ballerina/constraint;
+
+@constraint:String {
+    length: {
+        value: 10,
+        message: "Length Exceeded!"
+    },
+    pattern: {
+        value: re `^[a-zA-Z0-9_]+$`,
+        message: "Incorrect Pattern"
+    }
+}
+public type St_ID string;
+
+public type StudentRecord record {
+    St_ID id;
+    @constraint:String { pattern: re `^[a-zA-Z]+$`}
+    string name?;
+};
+
+service /payloadV on new http:Listener(9090) {
+    resource function post pet(@http:Payload StudentRecord body) returns error? {
+        return;
+    }
+}
diff --git a/openapi-cli/src/test/resources/ballerina-to-openapi/expected_gen/arrayTypeResponse.yaml b/openapi-cli/src/test/resources/ballerina-to-openapi/expected_gen/arrayTypeResponse.yaml
index fbbb9956a..f0df4278f 100644
--- a/openapi-cli/src/test/resources/ballerina-to-openapi/expected_gen/arrayTypeResponse.yaml
+++ b/openapi-cli/src/test/resources/ballerina-to-openapi/expected_gen/arrayTypeResponse.yaml
@@ -51,6 +51,7 @@ components:
         id:
           type: string
         name:
+          maxLength: 14
           type: string
         description:
           type: string
diff --git a/openapi-cli/src/test/resources/ballerina-to-openapi/expected_gen/constraint-negative/negative_constNameRef.yaml b/openapi-cli/src/test/resources/ballerina-to-openapi/expected_gen/constraint-negative/negative_constNameRef.yaml
new file mode 100644
index 000000000..25ef29711
--- /dev/null
+++ b/openapi-cli/src/test/resources/ballerina-to-openapi/expected_gen/constraint-negative/negative_constNameRef.yaml
@@ -0,0 +1,68 @@
+openapi: 3.0.1
+info:
+  title: PayloadV
+  version: 0.0.0
+servers:
+  - url: "{server}:{port}/payloadV"
+    variables:
+      server:
+        default: http://localhost
+      port:
+        default: "9090"
+paths:
+  /pet:
+    post:
+      operationId: postPet
+      requestBody:
+        content:
+          application/json:
+            schema:
+              $ref: '#/components/schemas/StudentRecord'
+      responses:
+        "202":
+          description: Accepted
+        "400":
+          description: BadRequest
+        "500":
+          description: Internal server error
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/ErrorPayload'
+components:
+  schemas:
+    ErrorPayload:
+      type: object
+      properties:
+        reason:
+          type: string
+          description: Reason phrase
+        path:
+          type: string
+          description: Request path
+        method:
+          type: string
+          description: Method type of the request
+        message:
+          type: string
+          description: Error message
+        timestamp:
+          type: string
+          description: Timestamp of the error
+        status:
+          type: integer
+          description: Relevant HTTP status code
+          format: int32
+    StudentRecord:
+      required:
+        - id
+      type: object
+      properties:
+        id:
+          $ref: '#/components/schemas/St_ID'
+        num:
+          type: number
+          format: float
+    St_ID:
+      type: integer
+      format: int32
diff --git a/openapi-cli/src/test/resources/ballerina-to-openapi/expected_gen/constraint-negative/negative_date.yaml b/openapi-cli/src/test/resources/ballerina-to-openapi/expected_gen/constraint-negative/negative_date.yaml
new file mode 100644
index 000000000..bb66f2fe2
--- /dev/null
+++ b/openapi-cli/src/test/resources/ballerina-to-openapi/expected_gen/constraint-negative/negative_date.yaml
@@ -0,0 +1,120 @@
+openapi: 3.0.1
+info:
+  title: PayloadV
+  version: 0.0.0
+servers:
+  - url: "{server}:{port}/payloadV"
+    variables:
+      server:
+        default: http://localhost
+      port:
+        default: "9090"
+paths:
+  /pet:
+    post:
+      operationId: postPet
+      requestBody:
+        content:
+          application/json:
+            schema:
+              $ref: '#/components/schemas/RegDate'
+      responses:
+        "202":
+          description: Accepted
+        "400":
+          description: BadRequest
+        "500":
+          description: Internal server error
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/ErrorPayload'
+components:
+  schemas:
+    ErrorPayload:
+      type: object
+      properties:
+        reason:
+          type: string
+          description: Reason phrase
+        path:
+          type: string
+          description: Request path
+        method:
+          type: string
+          description: Method type of the request
+        message:
+          type: string
+          description: Error message
+        timestamp:
+          type: string
+          description: Timestamp of the error
+        status:
+          type: integer
+          description: Relevant HTTP status code
+          format: int32
+    MyDate:
+      $ref: '#/components/schemas/Date'
+    RegDate:
+      required:
+        - date
+      type: object
+      properties:
+        date:
+          $ref: '#/components/schemas/MyDate'
+        lastLogin:
+          $ref: '#/components/schemas/Date'
+    Seconds:
+      type: number
+      description: Holds the seconds as a decimal value.
+      format: double
+    OptionalTimeOfDayFields:
+      type: object
+      properties:
+        hour:
+          type: integer
+          format: int64
+        minute:
+          type: integer
+          format: int64
+        second:
+          $ref: '#/components/schemas/Seconds'
+    Date:
+      allOf:
+        - $ref: '#/components/schemas/DateFields'
+        - $ref: '#/components/schemas/OptionalTimeOfDayFields'
+        - type: object
+          properties:
+            utcOffset:
+              $ref: '#/components/schemas/ZoneOffset'
+    DateFields:
+      required:
+        - day
+        - month
+        - year
+      type: object
+      properties:
+        year:
+          type: integer
+          format: int64
+        month:
+          type: integer
+          format: int64
+        day:
+          type: integer
+          format: int64
+    ZoneOffset:
+      required:
+        - hours
+        - minutes
+      type: object
+      properties:
+        hours:
+          type: integer
+          format: int64
+        minutes:
+          type: integer
+          format: int64
+        seconds:
+          type: number
+          format: double
diff --git a/openapi-cli/src/test/resources/ballerina-to-openapi/expected_gen/constraint-negative/negative_patternInterpolation.yaml b/openapi-cli/src/test/resources/ballerina-to-openapi/expected_gen/constraint-negative/negative_patternInterpolation.yaml
new file mode 100644
index 000000000..53c30b738
--- /dev/null
+++ b/openapi-cli/src/test/resources/ballerina-to-openapi/expected_gen/constraint-negative/negative_patternInterpolation.yaml
@@ -0,0 +1,76 @@
+openapi: 3.0.1
+info:
+  title: PayloadV
+  version: 0.0.0
+servers:
+  - url: "{server}:{port}/payloadV"
+    variables:
+      server:
+        default: http://localhost
+      port:
+        default: "9090"
+paths:
+  /pet:
+    post:
+      operationId: postPet
+      requestBody:
+        content:
+          application/json:
+            schema:
+              $ref: '#/components/schemas/Emp'
+      responses:
+        "202":
+          description: Accepted
+        "400":
+          description: BadRequest
+        "500":
+          description: Internal server error
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/ErrorPayload'
+components:
+  schemas:
+    ErrorPayload:
+      type: object
+      properties:
+        reason:
+          type: string
+          description: Reason phrase
+        path:
+          type: string
+          description: Request path
+        method:
+          type: string
+          description: Method type of the request
+        message:
+          type: string
+          description: Error message
+        timestamp:
+          type: string
+          description: Timestamp of the error
+        status:
+          type: integer
+          description: Relevant HTTP status code
+          format: int32
+    PosID:
+      maxLength: 21
+      minLength: 21
+      type: string
+    Emp:
+      required:
+        - posId
+      type: object
+      properties:
+        posId:
+          $ref: '#/components/schemas/PosID'
+        code:
+          type: string
+        empID:
+          $ref: '#/components/schemas/EmpID'
+        name:
+          $ref: '#/components/schemas/Name'
+    EmpID:
+      type: string
+    Name:
+      type: string
diff --git a/openapi-cli/src/test/resources/ballerina-to-openapi/expected_gen/constraint/array.yaml b/openapi-cli/src/test/resources/ballerina-to-openapi/expected_gen/constraint/array.yaml
new file mode 100644
index 000000000..8177618df
--- /dev/null
+++ b/openapi-cli/src/test/resources/ballerina-to-openapi/expected_gen/constraint/array.yaml
@@ -0,0 +1,111 @@
+openapi: 3.0.1
+info:
+  title: PayloadV
+  version: 0.0.0
+servers:
+  - url: "{server}:{port}/payloadV"
+    variables:
+      server:
+        default: http://localhost
+      port:
+        default: "9090"
+paths:
+  /pet:
+    post:
+      operationId: postPet
+      requestBody:
+        content:
+          application/json:
+            schema:
+              $ref: '#/components/schemas/Person'
+      responses:
+        "202":
+          description: Accepted
+        "400":
+          description: BadRequest
+        "500":
+          description: Internal server error
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/ErrorPayload'
+components:
+  schemas:
+    PersonDetailsItemsString:
+      minLength: 7
+      type: string
+    School:
+      maxItems: 15
+      minItems: 15
+      type: array
+      items:
+        $ref: '#/components/schemas/SchoolName'
+    ErrorPayload:
+      type: object
+      properties:
+        reason:
+          type: string
+          description: Reason phrase
+        path:
+          type: string
+          description: Request path
+        method:
+          type: string
+          description: Method type of the request
+        message:
+          type: string
+          description: Error message
+        timestamp:
+          type: string
+          description: Timestamp of the error
+        status:
+          type: integer
+          description: Relevant HTTP status code
+          format: int32
+    PersonFeeItemsNumber:
+      maximum: 445.4
+      type: number
+      format: float
+    PersonLimitItemsInteger:
+      maximum: 67
+      type: integer
+      format: int32
+    Hobby:
+      maxItems: 5
+      minItems: 2
+      type: array
+      items:
+        $ref: '#/components/schemas/HobbyItemsString'
+    HobbyItemsString:
+      maxLength: 23
+      type: string
+    SchoolName:
+      minLength: 5
+      type: string
+    Person:
+      required:
+        - id
+      type: object
+      properties:
+        hobby:
+          $ref: '#/components/schemas/Hobby'
+        school:
+          $ref: '#/components/schemas/School'
+        Details:
+          maxItems: 5
+          type: array
+          items:
+            $ref: '#/components/schemas/PersonDetailsItemsString'
+        id:
+          type: integer
+          format: int64
+        fee:
+          type: array
+          items:
+            $ref: '#/components/schemas/PersonFeeItemsNumber'
+        limit:
+          type: array
+          description: The maximum number of items in the response (as set in the
+            query or by default).
+          items:
+            $ref: '#/components/schemas/PersonLimitItemsInteger'
diff --git a/openapi-cli/src/test/resources/ballerina-to-openapi/expected_gen/constraint/arrayRec.yaml b/openapi-cli/src/test/resources/ballerina-to-openapi/expected_gen/constraint/arrayRec.yaml
new file mode 100644
index 000000000..c88b1c4e1
--- /dev/null
+++ b/openapi-cli/src/test/resources/ballerina-to-openapi/expected_gen/constraint/arrayRec.yaml
@@ -0,0 +1,100 @@
+openapi: 3.0.1
+info:
+  title: PayloadV
+  version: 0.0.0
+servers:
+  - url: "{server}:{port}/payloadV"
+    variables:
+      server:
+        default: http://localhost
+      port:
+        default: "9090"
+paths:
+  /pet:
+    post:
+      operationId: postPet
+      requestBody:
+        content:
+          application/json:
+            schema:
+              $ref: '#/components/schemas/Person'
+      responses:
+        "202":
+          description: Accepted
+        "400":
+          description: BadRequest
+        "500":
+          description: Internal server error
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/ErrorPayload'
+components:
+  schemas:
+    PersonDetailsItemsString:
+      minLength: 7
+      type: string
+    ErrorPayload:
+      type: object
+      properties:
+        reason:
+          type: string
+          description: Reason phrase
+        path:
+          type: string
+          description: Request path
+        method:
+          type: string
+          description: Method type of the request
+        message:
+          type: string
+          description: Error message
+        timestamp:
+          type: string
+          description: Timestamp of the error
+        status:
+          type: integer
+          description: Relevant HTTP status code
+          format: int32
+    PersonFeeItemsNumber:
+      maximum: 445.4
+      type: number
+      format: float
+    PersonLimitItemsInteger:
+      maximum: 67
+      type: integer
+      format: int32
+    Hobby:
+      maxItems: 5
+      minItems: 2
+      type: array
+      items:
+        $ref: '#/components/schemas/HobbyItemsString'
+    HobbyItemsString:
+      maxLength: 23
+      type: string
+    Person:
+      required:
+        - id
+      type: object
+      properties:
+        hobby:
+          $ref: '#/components/schemas/Hobby'
+        Details:
+          maxItems: 5
+          type: array
+          items:
+            $ref: '#/components/schemas/PersonDetailsItemsString'
+        id:
+          type: integer
+          format: int64
+        fee:
+          type: array
+          items:
+            $ref: '#/components/schemas/PersonFeeItemsNumber'
+        limit:
+          type: array
+          description: The maximum number of items in the response (as set in the
+            query or by default).
+          items:
+            $ref: '#/components/schemas/PersonLimitItemsInteger'
diff --git a/openapi-cli/src/test/resources/ballerina-to-openapi/expected_gen/constraint/decimalMax.yaml b/openapi-cli/src/test/resources/ballerina-to-openapi/expected_gen/constraint/decimalMax.yaml
new file mode 100644
index 000000000..a5ae8767d
--- /dev/null
+++ b/openapi-cli/src/test/resources/ballerina-to-openapi/expected_gen/constraint/decimalMax.yaml
@@ -0,0 +1,68 @@
+openapi: 3.0.1
+info:
+  title: PayloadV
+  version: 0.0.0
+servers:
+  - url: "{server}:{port}/payloadV"
+    variables:
+      server:
+        default: http://localhost
+      port:
+        default: "9090"
+paths:
+  /pet:
+    post:
+      operationId: postPet
+      requestBody:
+        content:
+          application/json:
+            schema:
+              $ref: '#/components/schemas/School'
+      responses:
+        "202":
+          description: Accepted
+        "400":
+          description: BadRequest
+        "500":
+          description: Internal server error
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/ErrorPayload'
+components:
+  schemas:
+    School:
+      required:
+        - marks
+      type: object
+      properties:
+        marks:
+          $ref: '#/components/schemas/Marks'
+    ErrorPayload:
+      type: object
+      properties:
+        reason:
+          type: string
+          description: Reason phrase
+        path:
+          type: string
+          description: Request path
+        method:
+          type: string
+          description: Method type of the request
+        message:
+          type: string
+          description: Error message
+        timestamp:
+          type: string
+          description: Timestamp of the error
+        status:
+          type: integer
+          description: Relevant HTTP status code
+          format: int32
+    Marks:
+      maximum: 5.55
+      exclusiveMaximum: true
+      minimum: 2.55
+      type: number
+      format: double
diff --git a/openapi-cli/src/test/resources/ballerina-to-openapi/expected_gen/constraint/decimalMin.yaml b/openapi-cli/src/test/resources/ballerina-to-openapi/expected_gen/constraint/decimalMin.yaml
new file mode 100644
index 000000000..be9fd4ee0
--- /dev/null
+++ b/openapi-cli/src/test/resources/ballerina-to-openapi/expected_gen/constraint/decimalMin.yaml
@@ -0,0 +1,68 @@
+openapi: 3.0.1
+info:
+  title: PayloadV
+  version: 0.0.0
+servers:
+  - url: "{server}:{port}/payloadV"
+    variables:
+      server:
+        default: http://localhost
+      port:
+        default: "9090"
+paths:
+  /pet:
+    post:
+      operationId: postPet
+      requestBody:
+        content:
+          application/json:
+            schema:
+              $ref: '#/components/schemas/School'
+      responses:
+        "202":
+          description: Accepted
+        "400":
+          description: BadRequest
+        "500":
+          description: Internal server error
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/ErrorPayload'
+components:
+  schemas:
+    School:
+      required:
+        - marks
+      type: object
+      properties:
+        marks:
+          $ref: '#/components/schemas/Marks'
+    ErrorPayload:
+      type: object
+      properties:
+        reason:
+          type: string
+          description: Reason phrase
+        path:
+          type: string
+          description: Request path
+        method:
+          type: string
+          description: Method type of the request
+        message:
+          type: string
+          description: Error message
+        timestamp:
+          type: string
+          description: Timestamp of the error
+        status:
+          type: integer
+          description: Relevant HTTP status code
+          format: int32
+    Marks:
+      maximum: 5.55
+      minimum: 2.55
+      exclusiveMinimum: true
+      type: number
+      format: double
diff --git a/openapi-cli/src/test/resources/ballerina-to-openapi/expected_gen/constraint/decimalRec.yaml b/openapi-cli/src/test/resources/ballerina-to-openapi/expected_gen/constraint/decimalRec.yaml
new file mode 100644
index 000000000..be9fd4ee0
--- /dev/null
+++ b/openapi-cli/src/test/resources/ballerina-to-openapi/expected_gen/constraint/decimalRec.yaml
@@ -0,0 +1,68 @@
+openapi: 3.0.1
+info:
+  title: PayloadV
+  version: 0.0.0
+servers:
+  - url: "{server}:{port}/payloadV"
+    variables:
+      server:
+        default: http://localhost
+      port:
+        default: "9090"
+paths:
+  /pet:
+    post:
+      operationId: postPet
+      requestBody:
+        content:
+          application/json:
+            schema:
+              $ref: '#/components/schemas/School'
+      responses:
+        "202":
+          description: Accepted
+        "400":
+          description: BadRequest
+        "500":
+          description: Internal server error
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/ErrorPayload'
+components:
+  schemas:
+    School:
+      required:
+        - marks
+      type: object
+      properties:
+        marks:
+          $ref: '#/components/schemas/Marks'
+    ErrorPayload:
+      type: object
+      properties:
+        reason:
+          type: string
+          description: Reason phrase
+        path:
+          type: string
+          description: Request path
+        method:
+          type: string
+          description: Method type of the request
+        message:
+          type: string
+          description: Error message
+        timestamp:
+          type: string
+          description: Timestamp of the error
+        status:
+          type: integer
+          description: Relevant HTTP status code
+          format: int32
+    Marks:
+      maximum: 5.55
+      minimum: 2.55
+      exclusiveMinimum: true
+      type: number
+      format: double
diff --git a/openapi-cli/src/test/resources/ballerina-to-openapi/expected_gen/constraint/floatMax.yaml b/openapi-cli/src/test/resources/ballerina-to-openapi/expected_gen/constraint/floatMax.yaml
new file mode 100644
index 000000000..5ba332e92
--- /dev/null
+++ b/openapi-cli/src/test/resources/ballerina-to-openapi/expected_gen/constraint/floatMax.yaml
@@ -0,0 +1,68 @@
+openapi: 3.0.1
+info:
+  title: PayloadV
+  version: 0.0.0
+servers:
+  - url: "{server}:{port}/payloadV"
+    variables:
+      server:
+        default: http://localhost
+      port:
+        default: "9090"
+paths:
+  /pet:
+    post:
+      operationId: postPet
+      requestBody:
+        content:
+          application/json:
+            schema:
+              $ref: '#/components/schemas/Hotel'
+      responses:
+        "202":
+          description: Accepted
+        "400":
+          description: BadRequest
+        "500":
+          description: Internal server error
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/ErrorPayload'
+components:
+  schemas:
+    ErrorPayload:
+      type: object
+      properties:
+        reason:
+          type: string
+          description: Reason phrase
+        path:
+          type: string
+          description: Request path
+        method:
+          type: string
+          description: Method type of the request
+        message:
+          type: string
+          description: Error message
+        timestamp:
+          type: string
+          description: Timestamp of the error
+        status:
+          type: integer
+          description: Relevant HTTP status code
+          format: int32
+    Rating:
+      maximum: 10.5
+      exclusiveMaximum: true
+      minimum: 2.5
+      type: number
+      format: float
+    Hotel:
+      required:
+        - rate
+      type: object
+      properties:
+        rate:
+          $ref: '#/components/schemas/Rating'
diff --git a/openapi-cli/src/test/resources/ballerina-to-openapi/expected_gen/constraint/floatMin.yaml b/openapi-cli/src/test/resources/ballerina-to-openapi/expected_gen/constraint/floatMin.yaml
new file mode 100644
index 000000000..6235704e6
--- /dev/null
+++ b/openapi-cli/src/test/resources/ballerina-to-openapi/expected_gen/constraint/floatMin.yaml
@@ -0,0 +1,68 @@
+openapi: 3.0.1
+info:
+  title: PayloadV
+  version: 0.0.0
+servers:
+  - url: "{server}:{port}/payloadV"
+    variables:
+      server:
+        default: http://localhost
+      port:
+        default: "9090"
+paths:
+  /pet:
+    post:
+      operationId: postPet
+      requestBody:
+        content:
+          application/json:
+            schema:
+              $ref: '#/components/schemas/Hotel'
+      responses:
+        "202":
+          description: Accepted
+        "400":
+          description: BadRequest
+        "500":
+          description: Internal server error
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/ErrorPayload'
+components:
+  schemas:
+    ErrorPayload:
+      type: object
+      properties:
+        reason:
+          type: string
+          description: Reason phrase
+        path:
+          type: string
+          description: Request path
+        method:
+          type: string
+          description: Method type of the request
+        message:
+          type: string
+          description: Error message
+        timestamp:
+          type: string
+          description: Timestamp of the error
+        status:
+          type: integer
+          description: Relevant HTTP status code
+          format: int32
+    Rating:
+      maximum: 10.5
+      minimum: 2.5
+      exclusiveMinimum: true
+      type: number
+      format: float
+    Hotel:
+      required:
+        - rate
+      type: object
+      properties:
+        rate:
+          $ref: '#/components/schemas/Rating'
diff --git a/openapi-cli/src/test/resources/ballerina-to-openapi/expected_gen/constraint/floatRec.yaml b/openapi-cli/src/test/resources/ballerina-to-openapi/expected_gen/constraint/floatRec.yaml
new file mode 100644
index 000000000..50d492486
--- /dev/null
+++ b/openapi-cli/src/test/resources/ballerina-to-openapi/expected_gen/constraint/floatRec.yaml
@@ -0,0 +1,68 @@
+openapi: 3.0.1
+info:
+  title: PayloadV
+  version: 0.0.0
+servers:
+  - url: "{server}:{port}/payloadV"
+    variables:
+      server:
+        default: http://localhost
+      port:
+        default: "9090"
+paths:
+  /pet:
+    post:
+      operationId: postPet
+      requestBody:
+        content:
+          application/json:
+            schema:
+              $ref: '#/components/schemas/Hotel'
+      responses:
+        "202":
+          description: Accepted
+        "400":
+          description: BadRequest
+        "500":
+          description: Internal server error
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/ErrorPayload'
+components:
+  schemas:
+    ErrorPayload:
+      type: object
+      properties:
+        reason:
+          type: string
+          description: Reason phrase
+        path:
+          type: string
+          description: Request path
+        method:
+          type: string
+          description: Method type of the request
+        message:
+          type: string
+          description: Error message
+        timestamp:
+          type: string
+          description: Timestamp of the error
+        status:
+          type: integer
+          description: Relevant HTTP status code
+          format: int32
+    Rating:
+      maximum: 10.5
+      exclusiveMaximum: true
+      minimum: 2.5
+      type: number
+      format: float
+      Hotel:
+        required:
+          - rate
+        type: object
+        properties:
+          rate:
+            $ref: '#/components/schemas/Rating'
diff --git a/openapi-cli/src/test/resources/ballerina-to-openapi/expected_gen/constraint/integerMax.yaml b/openapi-cli/src/test/resources/ballerina-to-openapi/expected_gen/constraint/integerMax.yaml
new file mode 100644
index 000000000..2701ab25b
--- /dev/null
+++ b/openapi-cli/src/test/resources/ballerina-to-openapi/expected_gen/constraint/integerMax.yaml
@@ -0,0 +1,68 @@
+openapi: 3.0.1
+info:
+  title: PayloadV
+  version: 0.0.0
+servers:
+  - url: "{server}:{port}/payloadV"
+    variables:
+      server:
+        default: http://localhost
+      port:
+        default: "9090"
+paths:
+  /pet:
+    post:
+      operationId: postPet
+      requestBody:
+        content:
+          application/json:
+            schema:
+              $ref: '#/components/schemas/Child'
+      responses:
+        "202":
+          description: Accepted
+        "400":
+          description: BadRequest
+        "500":
+          description: Internal server error
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/ErrorPayload'
+components:
+  schemas:
+    ErrorPayload:
+      type: object
+      properties:
+        reason:
+          type: string
+          description: Reason phrase
+        path:
+          type: string
+          description: Request path
+        method:
+          type: string
+          description: Method type of the request
+        message:
+          type: string
+          description: Error message
+        timestamp:
+          type: string
+          description: Timestamp of the error
+        status:
+          type: integer
+          description: Relevant HTTP status code
+          format: int32
+    Position:
+      maximum: 100
+      exclusiveMaximum: true
+      minimum: 10
+      type: integer
+      format: int32
+    Child:
+      required:
+        - position
+      type: object
+      properties:
+        position:
+          $ref: '#/components/schemas/Position'
diff --git a/openapi-cli/src/test/resources/ballerina-to-openapi/expected_gen/constraint/integerMin.yaml b/openapi-cli/src/test/resources/ballerina-to-openapi/expected_gen/constraint/integerMin.yaml
new file mode 100644
index 000000000..501ce9d42
--- /dev/null
+++ b/openapi-cli/src/test/resources/ballerina-to-openapi/expected_gen/constraint/integerMin.yaml
@@ -0,0 +1,68 @@
+openapi: 3.0.1
+info:
+  title: PayloadV
+  version: 0.0.0
+servers:
+  - url: "{server}:{port}/payloadV"
+    variables:
+      server:
+        default: http://localhost
+      port:
+        default: "9090"
+paths:
+  /pet:
+    post:
+      operationId: postPet
+      requestBody:
+        content:
+          application/json:
+            schema:
+              $ref: '#/components/schemas/Child'
+      responses:
+        "202":
+          description: Accepted
+        "400":
+          description: BadRequest
+        "500":
+          description: Internal server error
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/ErrorPayload'
+components:
+  schemas:
+    ErrorPayload:
+      type: object
+      properties:
+        reason:
+          type: string
+          description: Reason phrase
+        path:
+          type: string
+          description: Request path
+        method:
+          type: string
+          description: Method type of the request
+        message:
+          type: string
+          description: Error message
+        timestamp:
+          type: string
+          description: Timestamp of the error
+        status:
+          type: integer
+          description: Relevant HTTP status code
+          format: int32
+    Position:
+      maximum: 50
+      minimum: 0
+      exclusiveMinimum: true
+      type: integer
+      format: int32
+    Child:
+      required:
+        - position
+      type: object
+      properties:
+        position:
+          $ref: '#/components/schemas/Position'
diff --git a/openapi-cli/src/test/resources/ballerina-to-openapi/expected_gen/constraint/integerRec.yaml b/openapi-cli/src/test/resources/ballerina-to-openapi/expected_gen/constraint/integerRec.yaml
new file mode 100644
index 000000000..501ce9d42
--- /dev/null
+++ b/openapi-cli/src/test/resources/ballerina-to-openapi/expected_gen/constraint/integerRec.yaml
@@ -0,0 +1,68 @@
+openapi: 3.0.1
+info:
+  title: PayloadV
+  version: 0.0.0
+servers:
+  - url: "{server}:{port}/payloadV"
+    variables:
+      server:
+        default: http://localhost
+      port:
+        default: "9090"
+paths:
+  /pet:
+    post:
+      operationId: postPet
+      requestBody:
+        content:
+          application/json:
+            schema:
+              $ref: '#/components/schemas/Child'
+      responses:
+        "202":
+          description: Accepted
+        "400":
+          description: BadRequest
+        "500":
+          description: Internal server error
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/ErrorPayload'
+components:
+  schemas:
+    ErrorPayload:
+      type: object
+      properties:
+        reason:
+          type: string
+          description: Reason phrase
+        path:
+          type: string
+          description: Request path
+        method:
+          type: string
+          description: Method type of the request
+        message:
+          type: string
+          description: Error message
+        timestamp:
+          type: string
+          description: Timestamp of the error
+        status:
+          type: integer
+          description: Relevant HTTP status code
+          format: int32
+    Position:
+      maximum: 50
+      minimum: 0
+      exclusiveMinimum: true
+      type: integer
+      format: int32
+    Child:
+      required:
+        - position
+      type: object
+      properties:
+        position:
+          $ref: '#/components/schemas/Position'
diff --git a/openapi-cli/src/test/resources/ballerina-to-openapi/expected_gen/constraint/record_field.yaml b/openapi-cli/src/test/resources/ballerina-to-openapi/expected_gen/constraint/record_field.yaml
new file mode 100644
index 000000000..262772fe5
--- /dev/null
+++ b/openapi-cli/src/test/resources/ballerina-to-openapi/expected_gen/constraint/record_field.yaml
@@ -0,0 +1,92 @@
+openapi: 3.0.1
+info:
+  title: PayloadV
+  version: 0.0.0
+servers:
+  - url: "{server}:{port}/payloadV"
+    variables:
+      server:
+        default: http://localhost
+      port:
+        default: "9090"
+paths:
+  /pet:
+    post:
+      operationId: postPet
+      requestBody:
+        content:
+          application/json:
+            schema:
+              $ref: '#/components/schemas/Person'
+      responses:
+        "202":
+          description: Accepted
+        "400":
+          description: BadRequest
+        "500":
+          description: Internal server error
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/ErrorPayload'
+components:
+  schemas:
+    ErrorPayload:
+      type: object
+      properties:
+        reason:
+          type: string
+          description: Reason phrase
+        path:
+          type: string
+          description: Request path
+        method:
+          type: string
+          description: Method type of the request
+        message:
+          type: string
+          description: Error message
+        timestamp:
+          type: string
+          description: Timestamp of the error
+        status:
+          type: integer
+          description: Relevant HTTP status code
+          format: int32
+    Address:
+      minLength: 5
+      type: string
+    Person:
+      required:
+        - id
+      type: object
+      properties:
+        name:
+          maxLength: 14
+          type: string
+        hobby:
+          maxItems: 5
+          minItems: 2
+          type: array
+          items:
+            type: string
+        id:
+          maximum: 5
+          exclusiveMaximum: true
+          minimum: 0
+          type: integer
+          format: int64
+        address:
+          $ref: '#/components/schemas/Address'
+        salary:
+          maximum: 100000.0
+          exclusiveMaximum: true
+          minimum: 1000.0
+          type: number
+          format: float
+        net:
+          maximum: 1000000.0
+          minimum: 500000.0
+          exclusiveMinimum: true
+          type: number
+          format: double
diff --git a/openapi-cli/src/test/resources/ballerina-to-openapi/expected_gen/constraint/record_fieldRec.yaml b/openapi-cli/src/test/resources/ballerina-to-openapi/expected_gen/constraint/record_fieldRec.yaml
new file mode 100644
index 000000000..262772fe5
--- /dev/null
+++ b/openapi-cli/src/test/resources/ballerina-to-openapi/expected_gen/constraint/record_fieldRec.yaml
@@ -0,0 +1,92 @@
+openapi: 3.0.1
+info:
+  title: PayloadV
+  version: 0.0.0
+servers:
+  - url: "{server}:{port}/payloadV"
+    variables:
+      server:
+        default: http://localhost
+      port:
+        default: "9090"
+paths:
+  /pet:
+    post:
+      operationId: postPet
+      requestBody:
+        content:
+          application/json:
+            schema:
+              $ref: '#/components/schemas/Person'
+      responses:
+        "202":
+          description: Accepted
+        "400":
+          description: BadRequest
+        "500":
+          description: Internal server error
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/ErrorPayload'
+components:
+  schemas:
+    ErrorPayload:
+      type: object
+      properties:
+        reason:
+          type: string
+          description: Reason phrase
+        path:
+          type: string
+          description: Request path
+        method:
+          type: string
+          description: Method type of the request
+        message:
+          type: string
+          description: Error message
+        timestamp:
+          type: string
+          description: Timestamp of the error
+        status:
+          type: integer
+          description: Relevant HTTP status code
+          format: int32
+    Address:
+      minLength: 5
+      type: string
+    Person:
+      required:
+        - id
+      type: object
+      properties:
+        name:
+          maxLength: 14
+          type: string
+        hobby:
+          maxItems: 5
+          minItems: 2
+          type: array
+          items:
+            type: string
+        id:
+          maximum: 5
+          exclusiveMaximum: true
+          minimum: 0
+          type: integer
+          format: int64
+        address:
+          $ref: '#/components/schemas/Address'
+        salary:
+          maximum: 100000.0
+          exclusiveMaximum: true
+          minimum: 1000.0
+          type: number
+          format: float
+        net:
+          maximum: 1000000.0
+          minimum: 500000.0
+          exclusiveMinimum: true
+          type: number
+          format: double
diff --git a/openapi-cli/src/test/resources/ballerina-to-openapi/expected_gen/constraint/string.yaml b/openapi-cli/src/test/resources/ballerina-to-openapi/expected_gen/constraint/string.yaml
new file mode 100644
index 000000000..1bc0be1be
--- /dev/null
+++ b/openapi-cli/src/test/resources/ballerina-to-openapi/expected_gen/constraint/string.yaml
@@ -0,0 +1,70 @@
+openapi: 3.0.1
+info:
+  title: PayloadV
+  version: 0.0.0
+servers:
+  - url: "{server}:{port}/payloadV"
+    variables:
+      server:
+        default: http://localhost
+      port:
+        default: "9090"
+paths:
+  /pet:
+    post:
+      operationId: postPet
+      requestBody:
+        content:
+          application/json:
+            schema:
+              $ref: '#/components/schemas/StudentRecord'
+      responses:
+        "202":
+          description: Accepted
+        "400":
+          description: BadRequest
+        "500":
+          description: Internal server error
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/ErrorPayload'
+components:
+  schemas:
+    ErrorPayload:
+      type: object
+      properties:
+        reason:
+          type: string
+          description: Reason phrase
+        path:
+          type: string
+          description: Request path
+        method:
+          type: string
+          description: Method type of the request
+        message:
+          type: string
+          description: Error message
+        timestamp:
+          type: string
+          description: Timestamp of the error
+        status:
+          type: integer
+          description: Relevant HTTP status code
+          format: int32
+    StudentRecord:
+      required:
+        - id
+      type: object
+      properties:
+        id:
+          $ref: '#/components/schemas/St_ID'
+        name:
+          pattern: "^[a-zA-Z]+$"
+          type: string
+    St_ID:
+      maxLength: 10
+      minLength: 10
+      pattern: "^[a-zA-Z0-9_]+$"
+      type: string
diff --git a/openapi-cli/src/test/resources/ballerina-to-openapi/expected_gen/constraint/stringRec.yaml b/openapi-cli/src/test/resources/ballerina-to-openapi/expected_gen/constraint/stringRec.yaml
new file mode 100644
index 000000000..1bc0be1be
--- /dev/null
+++ b/openapi-cli/src/test/resources/ballerina-to-openapi/expected_gen/constraint/stringRec.yaml
@@ -0,0 +1,70 @@
+openapi: 3.0.1
+info:
+  title: PayloadV
+  version: 0.0.0
+servers:
+  - url: "{server}:{port}/payloadV"
+    variables:
+      server:
+        default: http://localhost
+      port:
+        default: "9090"
+paths:
+  /pet:
+    post:
+      operationId: postPet
+      requestBody:
+        content:
+          application/json:
+            schema:
+              $ref: '#/components/schemas/StudentRecord'
+      responses:
+        "202":
+          description: Accepted
+        "400":
+          description: BadRequest
+        "500":
+          description: Internal server error
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/ErrorPayload'
+components:
+  schemas:
+    ErrorPayload:
+      type: object
+      properties:
+        reason:
+          type: string
+          description: Reason phrase
+        path:
+          type: string
+          description: Request path
+        method:
+          type: string
+          description: Method type of the request
+        message:
+          type: string
+          description: Error message
+        timestamp:
+          type: string
+          description: Timestamp of the error
+        status:
+          type: integer
+          description: Relevant HTTP status code
+          format: int32
+    StudentRecord:
+      required:
+        - id
+      type: object
+      properties:
+        id:
+          $ref: '#/components/schemas/St_ID'
+        name:
+          pattern: "^[a-zA-Z]+$"
+          type: string
+    St_ID:
+      maxLength: 10
+      minLength: 10
+      pattern: "^[a-zA-Z0-9_]+$"
+      type: string
diff --git a/openapi-cli/src/test/resources/testng.xml b/openapi-cli/src/test/resources/testng.xml
index 48633fc0b..812a06d2d 100644
--- a/openapi-cli/src/test/resources/testng.xml
+++ b/openapi-cli/src/test/resources/testng.xml
@@ -42,6 +42,8 @@ under the License.
             
             
             
+            
+