From 499e3be24c38fff80035b92e03ddc539d7feabf3 Mon Sep 17 00:00:00 2001 From: Tharika Madurapperuma Date: Wed, 18 Sep 2024 12:44:12 +0530 Subject: [PATCH] Improve product rest api error responses for publisher --- .../carbon/apimgt/api/ExceptionCodes.java | 105 ++++++++++++++++++ .../carbon/apimgt/impl/APIProviderImpl.java | 67 +++++++---- .../impl/definitions/OASParserUtil.java | 3 +- .../carbon/apimgt/impl/utils/APIUtil.java | 46 +++++--- .../apimgt/impl/utils/LifeCycleUtils.java | 9 +- .../src/main/resources/publisher-api.yaml | 5 +- .../v1/dto/APIRevisionDeploymentDTO.java | 2 +- .../v1/common/ImportExportAPIServiceImpl.java | 6 +- .../v1/common/mappings/ImportUtils.java | 34 ++++-- .../common/mappings/PublisherCommonUtils.java | 59 ++++++---- .../v1/impl/ApiProductsApiServiceImpl.java | 43 ++++--- .../publisher/v1/impl/ApisApiServiceImpl.java | 45 +++++--- .../src/main/resources/publisher-api.yaml | 1 + 13 files changed, 312 insertions(+), 113 deletions(-) diff --git a/components/apimgt/org.wso2.carbon.apimgt.api/src/main/java/org/wso2/carbon/apimgt/api/ExceptionCodes.java b/components/apimgt/org.wso2.carbon.apimgt.api/src/main/java/org/wso2/carbon/apimgt/api/ExceptionCodes.java index e2f3f42ef8fc..2425e93c8085 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.api/src/main/java/org/wso2/carbon/apimgt/api/ExceptionCodes.java +++ b/components/apimgt/org.wso2.carbon.apimgt.api/src/main/java/org/wso2/carbon/apimgt/api/ExceptionCodes.java @@ -629,6 +629,111 @@ public enum ExceptionCodes implements ErrorHandler { ENDPOINT_SECURITY_TYPE_NOT_DEFINED(903214, "Endpoint security type not defined", 400, "Endpoint security type not defined for the %s endpoint", false), + ADDITIONAL_PROPERTIES_CANNOT_BE_NULL(903215, "'additionalProperties' is required and should " + + "not be null", 400, + "The field 'additionalProperties' is required and should not be null"), + + ADDITIONAL_PROPERTIES_PARSE_ERROR(903216, "Error while parsing 'additionalProperties'", 400, + "Error while parsing 'additionalProperties'", true), + + ENDPOINT_SECURITY_CRYPTO_EXCEPTION(903217, "Error while encrypting the secret key of API", 500, + "%s"), + + OPENAPI_RETRIEVAL_ERROR(903218, "Error while retrieving the OAS definition", 500, + "Error while retrieving the OAS definition for API with UUID %s"), + + ASYNCAPI_RETRIEVAL_ERROR(903219, "Error while retrieving the Async API definition", 500, + "Error while retrieving the Async API definition for API with UUID %s"), + + ERROR_RETRIEVING_API(903220, "Failed to get API", 500, "Failed to get API with UUID %s"), + + ERROR_CHANGING_REGISTRY_LIFECYCLE_STATE(903221, "Error changing registry lifecycle state", 500, + "Error changing registry lifecycle state for API/API Product with UUID %s"), + + UN_AUTHORIZED_TO_VIEW_MODIFY_API(903222, "User is not authorized to view or modify the api", + 403, "User %s is not authorized to view or modify the api"), + + FAILED_PUBLISHING_API_NO_ENDPOINT_SELECTED(903223, "Failed to publish service to API store. No endpoint selected", + 400, "Failed to publish service to API store. No endpoint selected for API with UUID %s"), + + FAILED_PUBLISHING_API_NO_TIERS_SELECTED(903224, "Failed to publish service to API store. No Tiers selected", + 400, "Failed to publish service to API store. No Tiers selected for API with UUID %s"), + + THIRD_PARTY_API_REVISION_CREATION_UNSUPPORTED(903225, "Creating API Revisions is not supported " + + "for third party APIs", 400,"Creating API Revisions is not supported for third party APIs: %s"), + + THIRD_PARTY_API_REVISION_DEPLOYMENT_UNSUPPORTED(903226, "Deploying API Revisions is not supported " + + "for third party APIs", 400,"Deploying API Revisions is not supported for third party APIs: %s"), + + RETIRED_API_REVISION_DEPLOYMENT_UNSUPPORTED(903227, "Deploying API Revisions is not supported for retired APIs", + 400, "Deploying API Revisions is not supported for retired APIs. ApiId: %s"), + + REVISION_NOT_FOUND_FOR_REVISION_NUMBER(903228, "No revision found", 404, + "No revision found for revision number %s"), + + ERROR_PROCESSING_DIRECTORY_TO_IMPORT(903229, "Error extracting and processing the directory", 500, + "Error extracting and processing the directory to be imported", true), + + IMPORT_ERROR_INVALID_GRAPHQL_SCHEMA(903230, "Error occurred while importing the API. Invalid " + + "GraphQL schema definition found", 400, "Invalid GraphQL schema definition " + + "found. %s"), + + IMPORT_ERROR_INVALID_ASYNC_API_SCHEMA(903231, "Error occurred while importing the API. " + + "Invalid AsyncAPI definition found.", 400, "Invalid AsyncAPI definition found. %s"), + + NO_VHOSTS_DEFINED_FOR_ENVIRONMENT(903232, "No VHosts defined for the environment", 400, + "No VHosts defined for the environment: %s"), + + PROVIDED_GATEWAY_ENVIRONMENT_NOT_FOUND(903233, "Gateway environment not found", 400, + "Provided gateway environment %s is not found"), + + UNSUPPORTED_AND_ALLOWED_LIFECYCLE_ACTIONS(903234, "Unsupported state change action", 400, + "Lifecycle state change action %s is not allowed for this API. Allowed actions are %s"), + + NO_CORRESPONDING_RESOURCE_FOUND_IN_API(903235, "No corresponding resource found in API", 400, + "API with id %s does not have a resource %s with http method %s"), + + ERROR_PARSING_MONETIZATION_PROPERTIES(903237, "Error when parsing monetization properties", + 400, "Error when parsing monetization properties"), + + API_NAME_CANNOT_BE_NULL(903238, "API name is required", 400, + "API name is required and cannot be null"), + + API_NAME_ILLEGAL_CHARACTERS(903239, "API name contains illegal characters", 400, + "API name %s contains one or more illegal characters from (%s)"), + + API_VERSION_CANNOT_BE_NULL(903240, "API version is required", 400, + "API version is required and cannot be null"), + + API_VERSION_ILLEGAL_CHARACTERS(903241, "API version contains illegal characters", 400, + "API version %s contains one or more illegal characters from (%s)"), + + UNSUPPORTED_CONTEXT(903242, "Unsupported context", 400, + "Unsupported context %s"), + + ERROR_PARSING_ENDPOINT_CONFIG(903243, "Error when parsing endpoint configuration", + 400, "Error when parsing endpoint configuration"), + + NOT_IN_OPEN_API_FORMAT(903244, "Not in Open API format", + 400, "The API definition is not in Open API format"), + + PARAMETER_NOT_PROVIDED_FOR_DOCUMENTATION(903245, "Parameter value missing", 400, + "Some of the mandatory parameter values were missing. %s"), + + INVALID_API_RESOURCES_FOR_API_PRODUCT(903246, "Cannot find API resources for some API Product " + + "resources.", 404, "Some of the resources in the API Product are not found as API resources. %s"), + + INVALID_ADDITIONAL_PROPERTIES_WITH_ERROR(903247, "Invalid additional properties", 400, + "Invalid additional properties for API: %s:%s Error: %s"), + + TIER_NAME_INVALID_WITH_TIER_INFO(903248, "The tier name is invalid.", 400, + "The tier name(s) %s are invalid"), + + LENGTH_EXCEEDS_ERROR(903249, "Character length exceeds the allowable limit", 400, "%s"), + + ROLE_OF_SCOPE_DOES_NOT_EXIST(903250, "Role does not exist", 404, + "Role %s does not exist"), + OPERATION_OR_RESOURCE_TYPE_OR_METHOD_NOT_DEFINED(902031, "Operation type/http method is not specified for the operation/resource", 400, "Operation type/http method is not specified for the operation/resource: %s", false), diff --git a/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/APIProviderImpl.java b/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/APIProviderImpl.java index 11eb10bc9343..5848a8a7daa8 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/APIProviderImpl.java +++ b/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/APIProviderImpl.java @@ -2038,8 +2038,10 @@ public API createNewAPIVersion(String existingApiId, String newVersion, Boolean ExceptionCodes.from(ExceptionCodes.API_NOT_FOUND, existingApiId)); } if (newVersion.equals(existingAPI.getId().getVersion())) { - throw new APIMgtResourceAlreadyExistsException( - "Version " + newVersion + " exists for api " + existingAPI.getId().getApiName()); + String errorMessage = "Version " + newVersion + " exists for api " + existingAPI.getId().getApiName(); + throw new APIMgtResourceAlreadyExistsException(errorMessage, + ExceptionCodes.from(ExceptionCodes.API_VERSION_ALREADY_EXISTS, newVersion, + existingAPI.getId().getApiName())); } if (APIUtil.isSequenceDefined(existingAPI.getInSequence()) || APIUtil.isSequenceDefined(existingAPI.getOutSequence()) || APIUtil.isSequenceDefined(existingAPI.getFaultSequence())) { @@ -3108,6 +3110,7 @@ public void updateAPIProductSwagger(String productId, Map checklist) throws APIManagementException{ APIStateChangeResponse response = new APIStateChangeResponse(); + String uuid = null; try { PrivilegedCarbonContext.startTenantFlow(); PrivilegedCarbonContext.getThreadLocalCarbonContext().setUsername(this.username); @@ -3120,7 +3123,6 @@ public APIStateChangeResponse changeLifeCycleStatus(String orgId, ApiTypeWrapper String apiType; String apiVersion; String currentStatus; - String uuid; int apiOrApiProductId; boolean isApiProduct = apiTypeWrapper.isAPIProduct(); String workflowType; @@ -3185,7 +3187,8 @@ public APIStateChangeResponse changeLifeCycleStatus(String orgId, ApiTypeWrapper APIConstants.AuditLogConstants.LIFECYCLE_CHANGED, this.username); } } catch (APIPersistenceException e) { - handleException("Error while accessing persistence layer", e); + throw new APIManagementException("Error while accessing persistence layer", e, + ExceptionCodes.from(ExceptionCodes.ERROR_CHANGING_REGISTRY_LIFECYCLE_STATE, uuid)); } finally { PrivilegedCarbonContext.endTenantFlow(); } @@ -4420,9 +4423,10 @@ private static void validateAPIProductContextTemplate(APIProduct product) throws //Validate if the API Product has an unsupported context before executing the query String invalidContext = "/" + APIConstants.VERSION_PLACEHOLDER; if (invalidContext.equals(contextTemplate)) { - throw new APIManagementException( - "Cannot add API Product : " + product.getId() + " with unsupported context : " - + contextTemplate); + String errorMessage = "Cannot add API Product : " + product.getId() + " with unsupported context : " + + contextTemplate; + throw new APIManagementException(errorMessage, + ExceptionCodes.from(ExceptionCodes.UNSUPPORTED_CONTEXT, contextTemplate)); } } @@ -4590,9 +4594,13 @@ public Map> updateAPIProduct(APIProduct product) uriTemplate.setId(templateMap.get(key).getId()); } else { - throw new APIManagementException("API with id " + apiProductResource.getApiId() + String errorMessage = "API with id " + apiProductResource.getApiId() + " does not have a resource " + uriTemplate.getUriTemplate() - + " with http method " + uriTemplate.getHTTPVerb()); + + " with http method " + uriTemplate.getHTTPVerb(); + throw new APIManagementException(errorMessage, + ExceptionCodes.from(ExceptionCodes.NO_CORRESPONDING_RESOURCE_FOUND_IN_API, + apiProductResource.getApiId(), uriTemplate.getUriTemplate(), + uriTemplate.getHTTPVerb())); } } } @@ -4617,7 +4625,9 @@ public Map> updateAPIProduct(APIProduct product) JSONObject jsonObj = (JSONObject) parser.parse(gson.toJson(newMonetizationProperties)); product.setMonetizationProperties(jsonObj); } catch (ParseException e) { - throw new APIManagementException("Error when parsing monetization properties ", e); + String errorMessage = "Error when parsing monetization properties "; + throw new APIManagementException(errorMessage, e, + ExceptionCodes.ERROR_PARSING_MONETIZATION_PROPERTIES); } } } @@ -4693,18 +4703,24 @@ private void validateApiLifeCycleForApiProducts(API api) throws APIManagementExc private void validateApiProductInfo(APIProduct product) throws APIManagementException { String apiName = product.getId().getName(); if (apiName == null) { - handleException("API Name is required."); + throw new APIManagementException("API Name is required.", ExceptionCodes.API_NAME_CANNOT_BE_NULL); } else if (containsIllegals(apiName)) { - handleException("API Name contains one or more illegal characters " + - "( " + APIConstants.REGEX_ILLEGAL_CHARACTERS_FOR_API_METADATA + " )"); + String errorMessage = "API Name contains one or more illegal characters ( " + + APIConstants.REGEX_ILLEGAL_CHARACTERS_FOR_API_METADATA + " )"; + throw new APIManagementException(errorMessage, + ExceptionCodes.from(ExceptionCodes.API_NAME_ILLEGAL_CHARACTERS, apiName, + APIConstants.REGEX_ILLEGAL_CHARACTERS_FOR_API_METADATA)); } String apiVersion = product.getId().getVersion(); if (apiVersion == null) { - handleException("API Version is required."); + throw new APIManagementException("API Version is required.", ExceptionCodes.API_VERSION_CANNOT_BE_NULL); } else if (containsIllegals(apiVersion)) { - handleException("API Version contains one or more illegal characters " + - "( " + APIConstants.REGEX_ILLEGAL_CHARACTERS_FOR_API_METADATA + " )"); + String errorMessage = "API Version contains one or more illegal characters ( " + + APIConstants.REGEX_ILLEGAL_CHARACTERS_FOR_API_METADATA + " )"; + throw new APIManagementException(errorMessage, + ExceptionCodes.from(ExceptionCodes.API_VERSION_ILLEGAL_CHARACTERS, apiVersion, + APIConstants.REGEX_ILLEGAL_CHARACTERS_FOR_API_METADATA)); } if (!hasValidLength(apiName, APIConstants.MAX_LENGTH_API_NAME) @@ -5246,13 +5262,17 @@ public API getAPIbyUUID(String uuid, String organization) throws APIManagementEx throw new APIMgtResourceNotFoundException(msg); } } catch (APIPersistenceException e) { - throw new APIManagementException("Failed to get API", e); + throw new APIManagementException("Failed to get API", e, + ExceptionCodes.from(ExceptionCodes.ERROR_RETRIEVING_API, uuid)); } catch (OASPersistenceException e) { - throw new APIManagementException("Error while retrieving the OAS definition", e); + throw new APIManagementException("Error while retrieving the OAS definition", e, + ExceptionCodes.from(ExceptionCodes.OPENAPI_RETRIEVAL_ERROR, uuid)); } catch (ParseException e) { - throw new APIManagementException("Error while parsing the OAS definition", e); + throw new APIManagementException("Error while parsing the OAS definition", e, + ExceptionCodes.from(ExceptionCodes.OPENAPI_PARSE_EXCEPTION, uuid)); } catch (AsyncSpecPersistenceException e) { - throw new APIManagementException("Error while retrieving the Async API definition", e); + throw new APIManagementException("Error while retrieving the Async API definition", e, + ExceptionCodes.from(ExceptionCodes.ASYNCAPI_RETRIEVAL_ERROR, uuid)); } } @@ -5517,7 +5537,7 @@ public API getLightweightAPIByUUID(String uuid, String organization) throws APIM } } catch (APIPersistenceException e) { String msg = "Failed to get API with uuid " + uuid; - throw new APIManagementException(msg, e); + throw new APIManagementException(msg, e, ExceptionCodes.from(ExceptionCodes.ERROR_RETRIEVING_API, uuid)); } } @@ -5741,8 +5761,9 @@ protected void checkAccessControlPermission(String userNameWithTenantDomain, Str return; } } - - throw new APIManagementException(APIConstants.UN_AUTHORIZED_ERROR_MESSAGE + " view or modify the api"); + String errorMessage = APIConstants.UN_AUTHORIZED_ERROR_MESSAGE + " view or modify the api"; + throw new APIManagementException(errorMessage, + ExceptionCodes.from(ExceptionCodes.UN_AUTHORIZED_TO_VIEW_MODIFY_API, username)); } } diff --git a/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/definitions/OASParserUtil.java b/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/definitions/OASParserUtil.java index 83f7b3471dc9..dfbef31f08b8 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/definitions/OASParserUtil.java +++ b/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/definitions/OASParserUtil.java @@ -274,7 +274,8 @@ public static String updateAPIProductSwaggerOperations(Map setEndpointSecurityForAPIProduct(API } return endpointSecurityMap; } catch (ParseException e) { - throw new APIManagementException("Error while parsing Endpoint Config json", e); + String errorMessage = "Error while parsing Endpoint Config json"; + throw new APIManagementException(errorMessage, e, ExceptionCodes.ERROR_PARSING_ENDPOINT_CONFIG); } } diff --git a/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/utils/LifeCycleUtils.java b/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/utils/LifeCycleUtils.java index 33377a0ece13..2340fe2c7459 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/utils/LifeCycleUtils.java +++ b/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/utils/LifeCycleUtils.java @@ -6,6 +6,7 @@ import org.json.simple.JSONObject; import org.wso2.carbon.apimgt.api.APIManagementException; import org.wso2.carbon.apimgt.api.APIProvider; +import org.wso2.carbon.apimgt.api.ExceptionCodes; import org.wso2.carbon.apimgt.api.model.*; import org.wso2.carbon.apimgt.impl.APIConstants; import org.wso2.carbon.apimgt.impl.dao.ApiMgtDAO; @@ -168,10 +169,14 @@ private static void changeAPILifeCycle(APIProvider apiProvider, API api, String || api.isAdvertiseOnly() && (api.getApiExternalProductionEndpoint() != null || api.getApiExternalSandboxEndpoint() != null)) { if ((isOauthProtected && (tiers == null || tiers.size() == 0)) && !api.isAdvertiseOnly()) { - throw new APIManagementException("Failed to publish service to API store. No Tiers selected"); + throw new APIManagementException("Failed to publish service to API store. No Tiers selected", + ExceptionCodes.from(ExceptionCodes.FAILED_PUBLISHING_API_NO_TIERS_SELECTED, + api.getUuid())); } } else { - throw new APIManagementException("Failed to publish service to API store. No endpoint selected"); + throw new APIManagementException("Failed to publish service to API store. No endpoint selected", + ExceptionCodes.from(ExceptionCodes.FAILED_PUBLISHING_API_NO_ENDPOINT_SELECTED, + api.getUuid())); } } diff --git a/components/apimgt/org.wso2.carbon.apimgt.rest.api.common/src/main/resources/publisher-api.yaml b/components/apimgt/org.wso2.carbon.apimgt.rest.api.common/src/main/resources/publisher-api.yaml index 3d0ff1a8a44c..6862991a9b92 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.rest.api.common/src/main/resources/publisher-api.yaml +++ b/components/apimgt/org.wso2.carbon.apimgt.rest.api.common/src/main/resources/publisher-api.yaml @@ -8167,7 +8167,7 @@ paths: x-code-samples: - lang: Curl source: 'curl -k -H "Authorization: Bearer ae4eae22-3f65-387b-a171-d37eaa366fa8" - -H "Content-Type: multipart/form-data" -F policySpecFile=@setHeader.yaml -F policyDefinitionFile=@setHeader.j2 + -H "Content-Type: multipart/form-data" -F policySpecFile=@setHeader.yaml -F synapsePolicyDefinitionFile=@setHeader.j2 "https://127.0.0.1:9443/api/am/publisher/v4/apis/96077508-fd01-4fae-bc64-5de0e2baf43c/operation-policies"' @@ -8411,7 +8411,7 @@ paths: x-code-samples: - lang: Curl source: 'curl -k -H "Authorization: Bearer ae4eae22-3f65-387b-a171-d37eaa366fa8" - -H "Content-Type: multipart/form-data" -F policySpecFile=@setHeader.yaml -F policyDefinitionFile=@setHeader.j2 + -H "Content-Type: multipart/form-data" -F policySpecFile=@setHeader.yaml -F synapsePolicyDefinitionFile=@setHeader.j2 "https://127.0.0.1:9443/api/am/publisher/v4/operation-policies"' /operation-policies/export: @@ -10194,6 +10194,7 @@ components: displayOnDevportal: type: boolean example: true + default: true deployedTime: readOnly: true type: string diff --git a/components/apimgt/org.wso2.carbon.apimgt.rest.api.publisher.v1.common/src/gen/java/org/wso2/carbon/apimgt/rest/api/publisher/v1/dto/APIRevisionDeploymentDTO.java b/components/apimgt/org.wso2.carbon.apimgt.rest.api.publisher.v1.common/src/gen/java/org/wso2/carbon/apimgt/rest/api/publisher/v1/dto/APIRevisionDeploymentDTO.java index ec1698c34b9c..21c6add149c5 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.rest.api.publisher.v1.common/src/gen/java/org/wso2/carbon/apimgt/rest/api/publisher/v1/dto/APIRevisionDeploymentDTO.java +++ b/components/apimgt/org.wso2.carbon.apimgt.rest.api.publisher.v1.common/src/gen/java/org/wso2/carbon/apimgt/rest/api/publisher/v1/dto/APIRevisionDeploymentDTO.java @@ -56,7 +56,7 @@ public static StatusEnum fromValue(String v) { } private StatusEnum status = StatusEnum.CREATED; private String vhost = null; - private Boolean displayOnDevportal = null; + private Boolean displayOnDevportal = true; private java.util.Date deployedTime = null; private java.util.Date successDeployedTime = null; diff --git a/components/apimgt/org.wso2.carbon.apimgt.rest.api.publisher.v1.common/src/main/java/org/wso2/carbon/apimgt/rest/api/publisher/v1/common/ImportExportAPIServiceImpl.java b/components/apimgt/org.wso2.carbon.apimgt.rest.api.publisher.v1.common/src/main/java/org/wso2/carbon/apimgt/rest/api/publisher/v1/common/ImportExportAPIServiceImpl.java index 050efd549c32..7a19f1c7b37c 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.rest.api.publisher.v1.common/src/main/java/org/wso2/carbon/apimgt/rest/api/publisher/v1/common/ImportExportAPIServiceImpl.java +++ b/components/apimgt/org.wso2.carbon.apimgt.rest.api.publisher.v1.common/src/main/java/org/wso2/carbon/apimgt/rest/api/publisher/v1/common/ImportExportAPIServiceImpl.java @@ -203,7 +203,8 @@ public ImportedAPIDTO importAPI(InputStream fileInputStream, Boolean preservePro try { extractedFolderPath = ImportUtils.getArchivePathOfExtractedDirectory(fileInputStream); } catch (APIImportExportException e) { - throw new APIManagementException(e); + throw new APIManagementException("Error extracting and processing the directory", e, + ExceptionCodes.ERROR_PROCESSING_DIRECTORY_TO_IMPORT); } return ImportUtils.importApi(extractedFolderPath, null, preserveProvider, rotateRevision, overwrite, preservePortalConfigurations, false, tokenScopes, null, organization); @@ -220,7 +221,8 @@ public APIProduct importAPIProduct(InputStream fileInputStream, Boolean preserve try { extractedFolderPath = ImportUtils.getArchivePathOfExtractedDirectory(fileInputStream); } catch (APIImportExportException e) { - throw new APIManagementException(e); + throw new APIManagementException("Error extracting and processing the directory", e, + ExceptionCodes.ERROR_PROCESSING_DIRECTORY_TO_IMPORT); } return ImportUtils.importApiProduct(extractedFolderPath, preserveProvider, rotateRevision, overwriteAPIProduct, overwriteAPIs, importAPIs, tokenScopes, organization); diff --git a/components/apimgt/org.wso2.carbon.apimgt.rest.api.publisher.v1.common/src/main/java/org/wso2/carbon/apimgt/rest/api/publisher/v1/common/mappings/ImportUtils.java b/components/apimgt/org.wso2.carbon.apimgt.rest.api.publisher.v1.common/src/main/java/org/wso2/carbon/apimgt/rest/api/publisher/v1/common/mappings/ImportUtils.java index 46f9bce00d0e..0fc63f39fb77 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.rest.api.publisher.v1.common/src/main/java/org/wso2/carbon/apimgt/rest/api/publisher/v1/common/mappings/ImportUtils.java +++ b/components/apimgt/org.wso2.carbon.apimgt.rest.api.publisher.v1.common/src/main/java/org/wso2/carbon/apimgt/rest/api/publisher/v1/common/mappings/ImportUtils.java @@ -901,8 +901,10 @@ private static List getValidatedDeploymentsList(JsonArray } else { // set the default vhost of the given environment if (gatewayEnvironment.getVhosts().isEmpty()) { - throw new APIManagementException("No VHosts defined for the environment: " - + deploymentName); + throw new APIManagementException( + "No VHosts defined for the environment: " + deploymentName, + ExceptionCodes.from(ExceptionCodes.NO_VHOSTS_DEFINED_FOR_ENVIRONMENT, + deploymentName)); } deploymentVhost = gatewayEnvironment.getVhosts().get(0).getHost(); } @@ -1496,9 +1498,11 @@ public static APIDefinitionValidationResponse retrieveValidatedAsyncApiDefinitio APIDefinitionValidationResponse validationResponse = AsyncApiParserUtil.validateAsyncAPISpecification(asyncApiDefinition, true); if (!validationResponse.isValid()) { - throw new APIManagementException( - "Error occurred while importing the API. Invalid AsyncAPI definition found. " - + validationResponse.getErrorItems()); + String errorMessage = "Error occurred while importing the API. Invalid AsyncAPI definition found. " + + validationResponse.getErrorItems(); + throw new APIManagementException(errorMessage, + ExceptionCodes.from(ExceptionCodes.IMPORT_ERROR_INVALID_ASYNC_API_SCHEMA, + StringUtils.join(validationResponse.getErrorItems(), ", "))); } return validationResponse; } catch (IOException e) { @@ -1543,9 +1547,11 @@ public static GraphQLValidationResponseDTO retrieveValidatedGraphqlSchemaFromArc GraphQLValidationResponseDTO graphQLValidationResponseDTO = PublisherCommonUtils .validateGraphQLSchema(file.getName(), schemaDefinition); if (!graphQLValidationResponseDTO.isIsValid()) { - throw new APIManagementException( - "Error occurred while importing the API. Invalid GraphQL schema definition found. " - + graphQLValidationResponseDTO.getErrorMessage()); + String errorMessage = "Error occurred while importing the API. Invalid GraphQL schema definition " + + "found. " + graphQLValidationResponseDTO.getErrorMessage(); + throw new APIManagementException(errorMessage, + ExceptionCodes.from(ExceptionCodes.IMPORT_ERROR_INVALID_GRAPHQL_SCHEMA, + graphQLValidationResponseDTO.getErrorMessage())); } return graphQLValidationResponseDTO; } catch (IOException e) { @@ -2670,7 +2676,7 @@ public static APIProduct importApiProduct(String extractedFolderPath, Boolean pr importedApiProduct.getId().getVersion()); } } else { - throw new APIManagementException(e); + throw e; } } @@ -2762,8 +2768,14 @@ private static void checkAPIProductResourcesValid(String path, String currentUse // Product does not have corresponding API resources neither inside the importing directory nor // inside the APIM if (!invalidApiOperations.isEmpty()) { - throw new APIMgtResourceNotFoundException( - "Cannot find API resources for some API Product resources."); + List invalidOperationList = new ArrayList(); + for (APIOperationsDTO dto : invalidApiOperations) { + invalidOperationList.add(dto.getVerb() + ":" + dto.getTarget()); + } + String errorMessage = "Cannot find API resources for some API Product resources."; + throw new APIMgtResourceNotFoundException(errorMessage, + ExceptionCodes.from(ExceptionCodes.INVALID_API_RESOURCES_FOR_API_PRODUCT, + StringUtils.join(invalidOperationList, ", "))); } } } diff --git a/components/apimgt/org.wso2.carbon.apimgt.rest.api.publisher.v1.common/src/main/java/org/wso2/carbon/apimgt/rest/api/publisher/v1/common/mappings/PublisherCommonUtils.java b/components/apimgt/org.wso2.carbon.apimgt.rest.api.publisher.v1.common/src/main/java/org/wso2/carbon/apimgt/rest/api/publisher/v1/common/mappings/PublisherCommonUtils.java index 1fba20fff132..3484e11d0796 100755 --- a/components/apimgt/org.wso2.carbon.apimgt.rest.api.publisher.v1.common/src/main/java/org/wso2/carbon/apimgt/rest/api/publisher/v1/common/mappings/PublisherCommonUtils.java +++ b/components/apimgt/org.wso2.carbon.apimgt.rest.api.publisher.v1.common/src/main/java/org/wso2/carbon/apimgt/rest/api/publisher/v1/common/mappings/PublisherCommonUtils.java @@ -850,8 +850,9 @@ public static void validateScopes(API api) throws APIManagementException { for (String aRole : scope.getRoles().split(",")) { boolean isValidRole = APIUtil.isRoleNameExist(username, aRole); if (!isValidRole) { - throw new APIManagementException("Role '" + aRole + "' does not exist.", - ExceptionCodes.ROLE_DOES_NOT_EXIST); + String errorMessage = "Role '" + aRole + "' does not exist."; + throw new APIManagementException(errorMessage, + ExceptionCodes.from(ExceptionCodes.ROLE_OF_SCOPE_DOES_NOT_EXIST, aRole)); } } } @@ -1519,7 +1520,9 @@ private static void prepareForUpdateSwagger(String apiId, APIDefinitionValidatio for (String aRole : roles.split(",")) { boolean isValidRole = APIUtil.isRoleNameExist(RestApiCommonUtil.getLoggedInUsername(), aRole); if (!isValidRole) { - throw new APIManagementException("Role '" + aRole + "' Does not exist."); + String errorMessage = "Role '" + aRole + "' Does not exist."; + throw new APIManagementException(errorMessage, + ExceptionCodes.from(ExceptionCodes.ROLE_OF_SCOPE_DOES_NOT_EXIST, aRole)); } } } @@ -1775,20 +1778,23 @@ public static Documentation addDocumentationToAPI(DocumentDTO documentDto, Strin ExceptionCodes.DOCUMENT_NAME_ILLEGAL_CHARACTERS); } if (documentDto.getType() == null) { - throw new APIManagementException("Documentation type cannot be empty", - ExceptionCodes.PARAMETER_NOT_PROVIDED); + String errorMessage = "Documentation type cannot be empty"; + throw new APIManagementException(errorMessage, + ExceptionCodes.from(ExceptionCodes.PARAMETER_NOT_PROVIDED_FOR_DOCUMENTATION, errorMessage)); } if (documentDto.getType() == DocumentDTO.TypeEnum.OTHER && StringUtils .isBlank(documentDto.getOtherTypeName())) { //check otherTypeName for not null if doc type is OTHER - throw new APIManagementException("otherTypeName cannot be empty if type is OTHER.", - ExceptionCodes.PARAMETER_NOT_PROVIDED); + String errorMessage = "otherTypeName cannot be empty if type is OTHER."; + throw new APIManagementException(errorMessage, + ExceptionCodes.from(ExceptionCodes.PARAMETER_NOT_PROVIDED_FOR_DOCUMENTATION, errorMessage)); } String sourceUrl = documentDto.getSourceUrl(); if (documentDto.getSourceType() == DocumentDTO.SourceTypeEnum.URL && ( org.apache.commons.lang3.StringUtils.isBlank(sourceUrl) || !RestApiCommonUtil.isURL(sourceUrl))) { - throw new APIManagementException("Invalid document sourceUrl Format", - ExceptionCodes.PARAMETER_NOT_PROVIDED); + String errorMessage = "Invalid document sourceUrl Format"; + throw new APIManagementException(errorMessage, + ExceptionCodes.from(ExceptionCodes.PARAMETER_NOT_PROVIDED_FOR_DOCUMENTATION, errorMessage)); } if (apiProvider.isDocumentationExist(apiId, documentName, organization)) { @@ -1898,17 +1904,19 @@ public static APIProduct updateApiProduct(APIProduct originalAPIProduct, APIProd Set definedTiers = apiProvider.getTiers(); List invalidTiers = PublisherCommonUtils.getInvalidTierNames(definedTiers, tiersFromDTO); if (!invalidTiers.isEmpty()) { - throw new APIManagementException( - "Specified tier(s) " + Arrays.toString(invalidTiers.toArray()) + " are invalid", - ExceptionCodes.TIER_NAME_INVALID); + String errorMessage = "Specified tier(s) " + Arrays.toString(invalidTiers.toArray()) + " are invalid"; + throw new APIManagementException(errorMessage, + ExceptionCodes.from(ExceptionCodes.TIER_NAME_INVALID_WITH_TIER_INFO, + Arrays.toString(invalidTiers.toArray()))); } if (apiProductDtoToUpdate.getAdditionalProperties() != null) { - String errorMessage = PublisherCommonUtils - .validateAdditionalProperties(apiProductDtoToUpdate.getAdditionalProperties()); + String errorMessage = PublisherCommonUtils.validateAdditionalProperties( + apiProductDtoToUpdate.getAdditionalProperties()); if (!errorMessage.isEmpty()) { - throw new APIManagementException(errorMessage, ExceptionCodes - .from(ExceptionCodes.INVALID_ADDITIONAL_PROPERTIES, originalAPIProduct.getId().getName(), - originalAPIProduct.getId().getVersion())); + throw new APIManagementException(errorMessage, + ExceptionCodes.from(ExceptionCodes.INVALID_ADDITIONAL_PROPERTIES_WITH_ERROR, + originalAPIProduct.getId().getName(), originalAPIProduct.getId().getVersion(), + errorMessage)); } } @@ -1970,16 +1978,18 @@ public static APIProduct addAPIProductWithGeneratedSwaggerDefinition(APIProductD Set definedTiers = apiProvider.getTiers(); List invalidTiers = PublisherCommonUtils.getInvalidTierNames(definedTiers, tiersFromDTO); if (!invalidTiers.isEmpty()) { - throw new APIManagementException( - "Specified tier(s) " + Arrays.toString(invalidTiers.toArray()) + " are invalid", - ExceptionCodes.TIER_NAME_INVALID); + String errorMessage = "Specified tier(s) " + Arrays.toString(invalidTiers.toArray()) + " are invalid"; + throw new APIManagementException(errorMessage, + ExceptionCodes.from(ExceptionCodes.TIER_NAME_INVALID_WITH_TIER_INFO, + Arrays.toString(invalidTiers.toArray()))); } if (apiProductDTO.getAdditionalProperties() != null) { String errorMessage = PublisherCommonUtils .validateAdditionalProperties(apiProductDTO.getAdditionalProperties()); if (!errorMessage.isEmpty()) { throw new APIManagementException(errorMessage, - ExceptionCodes.from(ExceptionCodes.INVALID_ADDITIONAL_PROPERTIES, apiProductDTO.getName())); + ExceptionCodes.from(ExceptionCodes.INVALID_ADDITIONAL_PROPERTIES_WITH_ERROR, + apiProductDTO.getName(), apiProductDTO.getVersion(), errorMessage)); } } if (apiProductDTO.getVisibility() == null) { @@ -2199,9 +2209,10 @@ public static APIStateChangeResponse changeApiOrApiProductLifecycle(String actio String[] nextAllowedStates = (String[]) apiLCData.get(APIConstants.LC_NEXT_STATES); if (!ArrayUtils.contains(nextAllowedStates, action)) { - throw new APIManagementException("Action '" + action + "' is not allowed. Allowed actions are " - + Arrays.toString(nextAllowedStates), ExceptionCodes.from(ExceptionCodes - .UNSUPPORTED_LIFECYCLE_ACTION, action)); + String errorMessage = "Action '" + action + "' is not allowed. Allowed actions are " + + Arrays.toString(nextAllowedStates); + throw new APIManagementException(errorMessage, ExceptionCodes.from(ExceptionCodes + .UNSUPPORTED_AND_ALLOWED_LIFECYCLE_ACTIONS, action, Arrays.toString(nextAllowedStates))); } //check and set lifecycle check list items including "Deprecate Old Versions" and "Require Re-Subscription". diff --git a/components/apimgt/org.wso2.carbon.apimgt.rest.api.publisher.v1/src/main/java/org/wso2/carbon/apimgt/rest/api/publisher/v1/impl/ApiProductsApiServiceImpl.java b/components/apimgt/org.wso2.carbon.apimgt.rest.api.publisher.v1/src/main/java/org/wso2/carbon/apimgt/rest/api/publisher/v1/impl/ApiProductsApiServiceImpl.java index be9bc6348bb7..62677dfa8259 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.rest.api.publisher.v1/src/main/java/org/wso2/carbon/apimgt/rest/api/publisher/v1/impl/ApiProductsApiServiceImpl.java +++ b/components/apimgt/org.wso2.carbon.apimgt.rest.api.publisher.v1/src/main/java/org/wso2/carbon/apimgt/rest/api/publisher/v1/impl/ApiProductsApiServiceImpl.java @@ -511,7 +511,7 @@ public Response getIsAPIProductOutdated(String apiProductId, String accept, Stri @Override public Response updateAPIProduct(String apiProductId, APIProductDTO body, String ifMatch, - MessageContext messageContext) { + MessageContext messageContext) throws APIManagementException { try { String username = RestApiCommonUtil.getLoggedInUsername(); String tenantDomain = RestApiCommonUtil.getLoggedInUserTenantDomain(); @@ -524,13 +524,15 @@ public Response updateAPIProduct(String apiProductId, APIProductDTO body, String apiProvider, username, tenantDomain); APIProductDTO updatedProductDTO = getAPIProductByID(apiProductId, apiProvider); return Response.ok().entity(updatedProductDTO).build(); - } catch (APIManagementException | FaultGatewaysException e) { + } catch (APIManagementException e) { if (isAuthorizationFailure(e)) { RestApiUtil.handleAuthorizationFailure("User is not authorized to access the API", e, log); } else { - String errorMessage = "Error while updating API Product : " + apiProductId; - RestApiUtil.handleInternalServerError(errorMessage, e, log); + throw e; } + } catch (FaultGatewaysException e) { + String errorMessage = "Error while updating API Product : " + apiProductId; + RestApiUtil.handleInternalServerError(errorMessage, e, log); } return null; } @@ -795,13 +797,15 @@ public Response getAllAPIProducts(Integer limit, Integer offset, String query, S RestApiConstants.RESOURCE_PATH_API_PRODUCTS + "/" + createdApiProductDTO.getId()); return Response.created(createdApiProductUri).entity(createdApiProductDTO).build(); - } catch (APIManagementException | FaultGatewaysException e) { + } catch (APIManagementException e) { if (e.getMessage().contains(ExceptionCodes.API_CONTEXT_MALFORMED_EXCEPTION.getErrorMessage())) { RestApiUtil.handleBadRequest("Error while adding new API Product. " + e.getMessage().replace("API", "API Product"), e, log); } - String errorMessage = "Error while adding new API Product : " + provider + "-" + body.getName() - + " - " + e.getMessage(); + throw e; + } catch (FaultGatewaysException e) { + String errorMessage = "Error while adding new API Product : " + provider + "-" + body.getName() + " - " + + e.getMessage(); RestApiUtil.handleInternalServerError(errorMessage, e, log); } catch (URISyntaxException e) { String errorMessage = "Error while retrieving API Product location : " + provider + "-" @@ -844,7 +848,11 @@ public Response createAPIProductRevision(String apiProductId, APIRevisionDTO apI return Response.created(createdApiUri).entity(createdApiRevisionDTO).build(); } catch (APIManagementException e) { String errorMessage = "Error while adding new API Revision for API Product: " + apiProductId; - RestApiUtil.handleInternalServerError(errorMessage, e, log); + if (e.getErrorHandler().getErrorCode() == ExceptionCodes.MAXIMUM_REVISIONS_REACHED.getErrorCode()) { + throw e; + } else { + RestApiUtil.handleInternalServerError(errorMessage, e, log); + } } catch (URISyntaxException e) { String errorMessage = "Error while retrieving created revision API location for API Product: " + apiProductId; @@ -877,16 +885,17 @@ public Response deployAPIProductRevision(String apiProductId, String revisionId, apiRevisionDeployment.setRevisionUUID(revisionId); String environment = apiRevisionDeploymentDTO.getName(); if (environments.get(environment) == null) { - RestApiUtil.handleBadRequest("Gateway environment not found: " + environment, log); + String errorMessage = "Gateway environment not found: " + environment; + throw new APIManagementException(errorMessage, + ExceptionCodes.from(ExceptionCodes.PROVIDED_GATEWAY_ENVIRONMENT_NOT_FOUND, environment)); } apiRevisionDeployment.setDeployment(environment); apiRevisionDeployment.setVhost(apiRevisionDeploymentDTO.getVhost()); if (StringUtils.isEmpty(apiRevisionDeploymentDTO.getVhost())) { - // vhost is only required when deploying an revision, not required when un-deploying a revision + // vhost is only required when deploying a revision, not required when un-deploying a revision // since the same scheme 'APIRevisionDeployment' is used for deploy and undeploy, handle it here. - RestApiUtil.handleBadRequest( - "Required field 'vhost' not found in deployment", log - ); + String errorMessage = "Required field 'vhost' not found in deployment"; + throw new APIManagementException(errorMessage, ExceptionCodes.GATEWAY_ENVIRONMENT_VHOST_NOT_PROVIDED); } apiRevisionDeployment.setDisplayOnDevportal(apiRevisionDeploymentDTO.isDisplayOnDevportal()); apiRevisionDeployments.add(apiRevisionDeployment); @@ -971,7 +980,9 @@ public Response undeployAPIProductRevision(String apiProductId, String revisionI if (revisionId == null && revisionNumber != null) { revisionId = apiProvider.getAPIRevisionUUID(revisionNumber, apiProductId); if (revisionId == null) { - return Response.status(Response.Status.BAD_REQUEST).entity(null).build(); + throw new APIManagementException( + "Revision " + revisionNumber + " is not found for API Product with UUID " + apiProductId, + ExceptionCodes.from(ExceptionCodes.API_REVISION_NOT_FOUND, revisionNumber)); } } String organization = RestApiUtil.getValidatedOrganization(messageContext); @@ -985,7 +996,9 @@ public Response undeployAPIProductRevision(String apiProductId, String revisionI apiRevisionDeployment.setRevisionUUID(revisionId); String environment = apiRevisionDeploymentDTO.getName(); if (environments.get(environment) == null) { - RestApiUtil.handleBadRequest("Gateway environment not found: " + environment, log); + String errorMessage = "Gateway environment not found: " + environment; + throw new APIManagementException(errorMessage, + ExceptionCodes.from(ExceptionCodes.PROVIDED_GATEWAY_ENVIRONMENT_NOT_FOUND, environment)); } apiRevisionDeployment.setDeployment(environment); apiRevisionDeployment.setVhost(apiRevisionDeploymentDTO.getVhost()); diff --git a/components/apimgt/org.wso2.carbon.apimgt.rest.api.publisher.v1/src/main/java/org/wso2/carbon/apimgt/rest/api/publisher/v1/impl/ApisApiServiceImpl.java b/components/apimgt/org.wso2.carbon.apimgt.rest.api.publisher.v1/src/main/java/org/wso2/carbon/apimgt/rest/api/publisher/v1/impl/ApisApiServiceImpl.java index f54d509c1006..779dff8069a4 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.rest.api.publisher.v1/src/main/java/org/wso2/carbon/apimgt/rest/api/publisher/v1/impl/ApisApiServiceImpl.java +++ b/components/apimgt/org.wso2.carbon.apimgt.rest.api.publisher.v1/src/main/java/org/wso2/carbon/apimgt/rest/api/publisher/v1/impl/ApisApiServiceImpl.java @@ -1829,7 +1829,7 @@ private LifecycleStateDTO getLifecycleState(String apiId, String organization) t } if (apiIdentifier == null) { throw new APIManagementException("Error while getting the api identifier for the API:" + - apiId, ExceptionCodes.INVALID_API_ID); + apiId, ExceptionCodes.from(ExceptionCodes.INVALID_API_ID, apiId)); } return PublisherCommonUtils.getLifecycleStateInformation(apiIdentifier, organization); } catch (APIManagementException e) { @@ -2882,7 +2882,8 @@ public Response importOpenAPIDefinition(InputStream fileInputStream, Attachment // validate 'additionalProperties' json if (StringUtils.isBlank(additionalProperties)) { - RestApiUtil.handleBadRequest("'additionalProperties' is required and should not be null", log); + throw new APIManagementException("'additionalProperties' is required and should not be null", + ExceptionCodes.ADDITIONAL_PROPERTIES_CANNOT_BE_NULL); } // Convert the 'additionalProperties' json into an APIDTO object @@ -2900,7 +2901,8 @@ public Response importOpenAPIDefinition(InputStream fileInputStream, Attachment ExceptionCodes.from(ExceptionCodes.API_CONTEXT_MALFORMED_EXCEPTION, e.getMessage())); } } catch (IOException e) { - throw RestApiUtil.buildBadRequestException("Error while parsing 'additionalProperties'", e); + throw new APIManagementException("Error while parsing 'additionalProperties'", e, + ExceptionCodes.ADDITIONAL_PROPERTIES_PARSE_ERROR); } // validate sandbox and production endpoints @@ -2934,7 +2936,8 @@ public Response importOpenAPIDefinition(InputStream fileInputStream, Attachment String errorMessage = "Error while encrypting the secret key of API : " + apiDTOFromProperties.getProvider() + "-" + apiDTOFromProperties.getName() + "-" + apiDTOFromProperties.getVersion(); - throw new APIManagementException(errorMessage, e); + throw new APIManagementException(errorMessage, e, + ExceptionCodes.from(ExceptionCodes.ENDPOINT_SECURITY_CRYPTO_EXCEPTION, errorMessage)); } return null; } @@ -3726,7 +3729,8 @@ public Response getAPIRevisions(String apiId, String query, MessageContext messa * @return response containing newly created APIRevision object */ @Override - public Response createAPIRevision(String apiId, APIRevisionDTO apIRevisionDTO, MessageContext messageContext) { + public Response createAPIRevision(String apiId, APIRevisionDTO apIRevisionDTO, MessageContext messageContext) + throws APIManagementException { try { APIProvider apiProvider = RestApiCommonUtil.getLoggedInUserProvider(); String organization = RestApiUtil.getValidatedOrganization(messageContext); @@ -3737,8 +3741,9 @@ public Response createAPIRevision(String apiId, APIRevisionDTO apIRevisionDTO, M //validate whether the API is advertise only APIDTO apiDto = getAPIByID(apiId, apiProvider, organization); if (apiDto != null && apiDto.getAdvertiseInfo() != null && apiDto.getAdvertiseInfo().isAdvertised()) { - throw new APIManagementException("Creating API Revisions is not supported for third party APIs: " - + apiId); + throw new APIManagementException( + "Creating API Revisions is not supported for third party APIs: " + apiId, + ExceptionCodes.from(ExceptionCodes.THIRD_PARTY_API_REVISION_CREATION_UNSUPPORTED, apiId)); } //validate API update operation permitted based on the LC state @@ -3760,7 +3765,14 @@ public Response createAPIRevision(String apiId, APIRevisionDTO apIRevisionDTO, M return Response.created(createdApiUri).entity(createdApiRevisionDTO).build(); } catch (APIManagementException e) { String errorMessage = "Error while adding new API Revision for API : " + apiId; - RestApiUtil.handleInternalServerError(errorMessage, e, log); + if ((e.getErrorHandler() + .getErrorCode() == ExceptionCodes.THIRD_PARTY_API_REVISION_CREATION_UNSUPPORTED.getErrorCode()) + || (e.getErrorHandler().getErrorCode() == ExceptionCodes.MAXIMUM_REVISIONS_REACHED.getErrorCode())) + { + throw e; + } else { + RestApiUtil.handleInternalServerError(errorMessage, e, log); + } } catch (URISyntaxException e) { String errorMessage = "Error while retrieving created revision API location for API : " + apiId; @@ -3841,12 +3853,15 @@ public Response deployAPIRevision(String apiId, String revisionId, APIDTO apiDto = getAPIByID(apiId, apiProvider, organization); // Reject the request if API lifecycle is 'RETIRED'. if (apiDto.getLifeCycleStatus().equals(APIConstants.RETIRED)) { - return Response.status(Response.Status.BAD_REQUEST).entity("Deploying API Revisions is not supported for retired APIs. ApiId: " - + apiId).build(); + String errorMessage = "Deploying API Revisions is not supported for retired APIs. ApiId: " + apiId; + throw new APIManagementException(errorMessage, + ExceptionCodes.from(ExceptionCodes.RETIRED_API_REVISION_DEPLOYMENT_UNSUPPORTED, apiId)); } - if (apiDto != null && apiDto.getAdvertiseInfo() != null && Boolean.TRUE.equals(apiDto.getAdvertiseInfo().isAdvertised())) { - throw new APIManagementException("Deploying API Revisions is not supported for third party APIs: " - + apiId); + if (apiDto != null && apiDto.getAdvertiseInfo() != null && Boolean.TRUE.equals( + apiDto.getAdvertiseInfo().isAdvertised())) { + String errorMessage = "Deploying API Revisions is not supported for third party APIs: " + apiId; + throw new APIManagementException(errorMessage, + ExceptionCodes.from(ExceptionCodes.THIRD_PARTY_API_REVISION_DEPLOYMENT_UNSUPPORTED, apiId)); } Map environments = APIUtil.getEnvironments(organization); @@ -3904,7 +3919,9 @@ public Response undeployAPIRevision(String apiId, String revisionId, String revi if (revisionId == null && revisionNum != null) { revisionId = apiProvider.getAPIRevisionUUID(revisionNum, apiId); if (revisionId == null) { - return Response.status(Response.Status.BAD_REQUEST).entity(null).build(); + throw new APIManagementException( + "No revision found for revision number " + revisionNum + " of API with UUID " + apiId, + ExceptionCodes.from(ExceptionCodes.REVISION_NOT_FOUND_FOR_REVISION_NUMBER, revisionNum)); } } diff --git a/components/apimgt/org.wso2.carbon.apimgt.rest.api.publisher.v1/src/main/resources/publisher-api.yaml b/components/apimgt/org.wso2.carbon.apimgt.rest.api.publisher.v1/src/main/resources/publisher-api.yaml index 7fa0e5807561..6862991a9b92 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.rest.api.publisher.v1/src/main/resources/publisher-api.yaml +++ b/components/apimgt/org.wso2.carbon.apimgt.rest.api.publisher.v1/src/main/resources/publisher-api.yaml @@ -10194,6 +10194,7 @@ components: displayOnDevportal: type: boolean example: true + default: true deployedTime: readOnly: true type: string