From 8e2eeca881a43d00d905cf0591c5c1bbbfe8d275 Mon Sep 17 00:00:00 2001 From: rmsamitha Date: Thu, 27 Jun 2024 15:19:53 +0530 Subject: [PATCH 1/2] Improving Error Responses for api create,update REST APIs --- .../carbon/apimgt/api/ExceptionCodes.java | 52 +++++++- .../carbon/apimgt/impl/APIProviderImpl.java | 119 ++++++++++++++++-- .../impl/GlobalMediationPolicyImpl.java | 10 ++ .../impl/definitions/OASParserUtil.java | 9 +- .../impl/internal/APIManagerComponent.java | 3 + .../impl/internal/ServiceReferenceHolder.java | 11 +- .../carbon/apimgt/impl/utils/APIUtil.java | 28 ++++- .../src/main/resources/publisher-api.yaml | 3 + .../publisher/v1/dto/APIOperationsDTO.java | 6 +- .../v1/common/mappings/APIMappingUtil.java | 50 +++++--- .../v1/common/mappings/ImportUtils.java | 2 +- .../common/mappings/PublisherCommonUtils.java | 37 +++++- .../publisher/v1/impl/ApisApiServiceImpl.java | 17 ++- .../src/main/resources/publisher-api.yaml | 3 + 14 files changed, 301 insertions(+), 49 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 ccdf582c748b..d34eda302d86 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 @@ -512,7 +512,7 @@ public enum ExceptionCodes implements ErrorHandler { INVALID_OPERATION_POLICY_SPECIFICATION(902006, "Invalid policy specification found", 400, "Invalid policy specification. %s", false), - INVALID_OPERATION_POLICY_PARAMETERS(902007, "Missing required parameters for policy specification", 400, + MISSING_OPERATION_POLICY_PARAMETERS(902007, "Missing required parameters for policy specification", 400, "Required parameter(s) %s for policy specification %s are either missing or empty"), OPERATION_POLICY_NOT_ALLOWED_IN_THE_APPLIED_FLOW(902008, "Policy is not allowed in the applied flow", 400, "%s policy is not allowed in applied flow"), @@ -545,8 +545,56 @@ public enum ExceptionCodes implements ErrorHandler { ARTIFACT_SYNC_HTTP_REQUEST_FAILED(903009, "Error while retrieving from remote endpoint", 500, "Error while executing HTTP request to retrieve from remote endpoint"), KEY_MANAGER_DELETE_FAILED(902013, "Key Manager Delete error", 412,"Key Manager Delete error. %s", false), KEYS_DELETE_FAILED(902014, "Key Delete error", 412,"Keys delete error. %s", false), - DOCUMENT_NAME_ILLEGAL_CHARACTERS(902015, "Document name cannot contain illegal characters", 400, "Document name contains one or more illegal characters"); + DOCUMENT_NAME_ILLEGAL_CHARACTERS(903200, "Document name cannot contain illegal characters", 400, + "Document name contains one or more illegal characters", false), + + HTTP_METHOD_INVALID(903201, + "Invalid HTTP method provided for API resource", 400, + "The HTTP method '%s' provided for resource '%s' is invalid", false), + + OPERATION_TYPE_INVALID(903202, "Invalid operation type provided for API operation", 400, + "The '%s' API operation type '%s' provided for operation '%s' is invalid", false), + + KEYMANAGERS_VALUE_NOT_ARRAY(903203, "KeyManagers value needs to be an array", 400, + "Value of the KeyManagers config should be an array", false), + + SCOPE_ALREADY_ASSIGNED_FOR_DIFFERENT_API(903204, "Invalid scopes provided for API", 400, + "Error while adding local scopes for API %s. Scope: %s already assigned locally for a different API.", + false), + + UNSUPPORTED_TRANSPORT(903205, "Unsupported transport", 400, + "Unsupported transport %s provided for the API operation/resource", false), + + OAS_DEFINITION_VERSION_NOT_FOUND(903206, "Invalid OAS definition", 400, + "Could not determine the OAS version as the version element of the definition is not found", false), + + API_NAME_PROVIDER_ORG_EMPTY(903207, "API name, provider or organization cannot be empty", 400, + "API name, provider or organization cannot be empty. Provided values: name: %s, provider: %s, org: %s", + false), + + ANONYMOUS_USER_NOT_PERMITTED(903208, "Anonymous user not permitted", 401, + "Attempt to execute privileged operation as the anonymous user", false), + + GLOBAL_MEDIATION_POLICIES_NOT_FOUND(903209, "Global mediation policies not found", 404, + "Global mediation policies not found", false), + + ENDPOINT_URL_NOT_PROVIDED(903210, "Endpoint url not provided", 400, + "Url is not provided for the endpoint type %s in the endpoint config", false), + + OPERATION_POLICY_NAME_VERSION_INVALID(903211, "Invalid operation policy name or version", 400, + "policyName and/or policyVersion provided for the applied policy %s_%s does not match the policy " + + "specification identified by the given policyId %s", + false), + + INVALID_OPERATION_POLICY_PARAMS(903212, "Invalid operation policy parameters", 400, + "Invalid value provided for the operation policy parameter %s", false), + + INVALID_ENDPOINT_SECURITY_CONFIG(903213, "Invalid endpoint security configuration", 400, + "Invalid values provided for %s endpoint security configuration", false), + + ENDPOINT_SECURITY_TYPE_NOT_DEFINED(903214, "Endpoint security type not defined", 400, + "Endpoint security type not defined for the %s endpoint", false); private final long errorCode; private final String errorMessage; 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 22d1c216e0b6..ecb337c6d25a 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 @@ -113,6 +113,8 @@ import java.util.regex.Pattern; import java.util.stream.Collectors; +import static org.wso2.carbon.apimgt.impl.utils.APIUtil.handleException; + /** * This class provides the core API provider functionality. It is implemented in a very * self-contained and 'pure' manner, without taking requirements like security into account, @@ -591,8 +593,10 @@ private Set getScopesToRegisterFromURITemplates(String apiName, String or if (!isScopeKeyAssignedLocally(apiName, scope.getKey(), organization)) { scopesToRegister.add(scope); } else { - throw new APIManagementException("Error while adding local scopes for API " + apiName - + ". Scope: " + scopeKey + " already assigned locally for a different API."); + String errMsg = "Error while adding local scopes for API " + apiName + + ". Scope: " + scopeKey + " already assigned locally for a different API."; + APIUtil.handleException(errMsg, ExceptionCodes + .from(ExceptionCodes.SCOPE_ALREADY_ASSIGNED_FOR_DIFFERENT_API, apiName, scopeKey)); } } else if (log.isDebugEnabled()) { log.debug("Scope " + scopeKey + " exists as a shared scope. Skip adding as a local scope."); @@ -1044,9 +1048,26 @@ private void updateEndpointSecurity(API oldApi, API api) throws APIManagementExc (JSONObject) oldEndpointConfigJson.get(APIConstants.ENDPOINT_SECURITY); if (endpointSecurityJson.get(APIConstants.ENDPOINT_SECURITY_PRODUCTION) != null) { if (oldEndpointSecurityJson.get(APIConstants.ENDPOINT_SECURITY_PRODUCTION) != null) { - EndpointSecurity endpointSecurity = new ObjectMapper().convertValue( - endpointSecurityJson.get(APIConstants.ENDPOINT_SECURITY_PRODUCTION), - EndpointSecurity.class); + EndpointSecurity endpointSecurity; + if (ServiceReferenceHolder.getInstance().isDetailedErrorResponsesEnabled()) { + try { + endpointSecurity = new ObjectMapper().convertValue( + endpointSecurityJson.get(APIConstants.ENDPOINT_SECURITY_PRODUCTION), + EndpointSecurity.class); + } catch (IllegalArgumentException e) { + ErrorHandler errorHandler = ExceptionCodes.from( + ExceptionCodes.INVALID_ENDPOINT_SECURITY_CONFIG, + APIConstants.ENDPOINT_SECURITY_PRODUCTION); + throw new APIManagementException( + "Error while processing " + APIConstants.ENDPOINT_SECURITY_PRODUCTION + " endpoint security configuration related values provided for API " + api.getId() + .toString(), errorHandler); + } + } else { + endpointSecurity = new ObjectMapper().convertValue( + endpointSecurityJson.get(APIConstants.ENDPOINT_SECURITY_PRODUCTION), + EndpointSecurity.class); + } + EndpointSecurity oldEndpointSecurity = new ObjectMapper().convertValue( oldEndpointSecurityJson.get(APIConstants.ENDPOINT_SECURITY_PRODUCTION), EndpointSecurity.class); @@ -1054,6 +1075,17 @@ private void updateEndpointSecurity(API oldApi, API api) throws APIManagementExc StringUtils.isBlank(endpointSecurity.getPassword())) { endpointSecurity.setUsername(oldEndpointSecurity.getUsername()); endpointSecurity.setPassword(oldEndpointSecurity.getPassword()); + if (ServiceReferenceHolder.getInstance().isDetailedErrorResponsesEnabled()) { + if (StringUtils.isBlank(endpointSecurity.getType())) { + ErrorHandler errorHandler = ExceptionCodes.from( + ExceptionCodes.ENDPOINT_SECURITY_TYPE_NOT_DEFINED, + APIConstants.ENDPOINT_SECURITY_PRODUCTION); + throw new APIManagementException("Endpoint security type is not defined " + + "for the endpoint type " + APIConstants.ENDPOINT_SECURITY_PRODUCTION, + errorHandler); + } + } + if (endpointSecurity.getType().equals(APIConstants.ENDPOINT_SECURITY_TYPE_OAUTH)) { endpointSecurity.setUniqueIdentifier(oldEndpointSecurity.getUniqueIdentifier()); endpointSecurity.setGrantType(oldEndpointSecurity.getGrantType()); @@ -1069,9 +1101,27 @@ private void updateEndpointSecurity(API oldApi, API api) throws APIManagementExc } if (endpointSecurityJson.get(APIConstants.ENDPOINT_SECURITY_SANDBOX) != null) { if (oldEndpointSecurityJson.get(APIConstants.ENDPOINT_SECURITY_SANDBOX) != null) { - EndpointSecurity endpointSecurity = new ObjectMapper() - .convertValue(endpointSecurityJson.get(APIConstants.ENDPOINT_SECURITY_SANDBOX), + EndpointSecurity endpointSecurity; + if (ServiceReferenceHolder.getInstance().isDetailedErrorResponsesEnabled()) { + try { + endpointSecurity = new ObjectMapper().convertValue( + endpointSecurityJson.get(APIConstants.ENDPOINT_SECURITY_SANDBOX), EndpointSecurity.class); + } catch (IllegalArgumentException e) { + ErrorHandler errorHandler = ExceptionCodes.from( + ExceptionCodes.INVALID_ENDPOINT_SECURITY_CONFIG, + APIConstants.ENDPOINT_SECURITY_SANDBOX); + throw new APIManagementException( + "Error while processing " + APIConstants.ENDPOINT_SECURITY_SANDBOX + + " endpoint security configuration related values provided for API " + api.getId() + .toString(), errorHandler); + } + } else { + endpointSecurity = new ObjectMapper().convertValue( + endpointSecurityJson.get(APIConstants.ENDPOINT_SECURITY_SANDBOX), + EndpointSecurity.class); + } + EndpointSecurity oldEndpointSecurity = new ObjectMapper() .convertValue(oldEndpointSecurityJson.get(APIConstants.ENDPOINT_SECURITY_SANDBOX), EndpointSecurity.class); @@ -1079,6 +1129,16 @@ private void updateEndpointSecurity(API oldApi, API api) throws APIManagementExc StringUtils.isBlank(endpointSecurity.getPassword())) { endpointSecurity.setUsername(oldEndpointSecurity.getUsername()); endpointSecurity.setPassword(oldEndpointSecurity.getPassword()); + if (ServiceReferenceHolder.getInstance().isDetailedErrorResponsesEnabled()) { + if (StringUtils.isBlank(endpointSecurity.getType())) { + ErrorHandler errorHandler = ExceptionCodes.from( + ExceptionCodes.ENDPOINT_SECURITY_TYPE_NOT_DEFINED, + APIConstants.ENDPOINT_SECURITY_SANDBOX); + throw new APIManagementException("Endpoint security type is not defined " + + "for the endpoint type " + APIConstants.ENDPOINT_SECURITY_SANDBOX, + errorHandler); + } + } if (endpointSecurity.getType().equals(APIConstants.ENDPOINT_SECURITY_TYPE_OAUTH)) { endpointSecurity.setUniqueIdentifier(oldEndpointSecurity.getUniqueIdentifier()); endpointSecurity.setGrantType(oldEndpointSecurity.getGrantType()); @@ -1636,6 +1696,16 @@ private List validatePolicies(List apiPolicies if (!commonPolicyData.getSpecification().getName() .equals(policy.getPolicyName()) || !commonPolicyData.getSpecification().getVersion() .equals(policy.getPolicyVersion())) { + if (ServiceReferenceHolder.getInstance().isDetailedErrorResponsesEnabled()) { + String errMsg = + "policyName and/or policyVersion provided for the applied policy " + policy.getPolicyName() + + "_" + policy.getPolicyVersion() + " does not match the policy " + + "specification identified by the given policyId " + policyId; + ErrorHandler errorHandler = ExceptionCodes.from( + ExceptionCodes.OPERATION_POLICY_NAME_VERSION_INVALID, policy.getPolicyName(), + policy.getPolicyVersion(), policyId); + throw new APIManagementException(errMsg, errorHandler); + } throw new APIManagementException("Applied policy for uriTemplate " + policy.getPolicyName() + "_" + policy.getPolicyVersion() + " does not match the specification"); } @@ -1718,11 +1788,34 @@ public boolean validateAppliedPolicyWithSpecification(OperationPolicySpecificati if (appliedPolicyAttribute != null) { if (attribute.getValidationRegex() != null) { Pattern pattern = Pattern.compile(attribute.getValidationRegex(), Pattern.CASE_INSENSITIVE); - Matcher matcher = pattern.matcher((String) appliedPolicyAttribute); + Matcher matcher; + if (ServiceReferenceHolder.getInstance().isDetailedErrorResponsesEnabled()) { + try { + matcher = pattern.matcher((String) appliedPolicyAttribute); + } catch (ClassCastException e) { + ErrorHandler errorHandler = ExceptionCodes.from( + ExceptionCodes.INVALID_OPERATION_POLICY_PARAMS, attribute.getName()); + throw new APIManagementException( + "Value with invalid data type provided for the operation policy " + + "parameter " + attribute.getName(), + errorHandler); + } + } else { + matcher = pattern.matcher((String) appliedPolicyAttribute); + } + if (!matcher.matches()) { - throw new APIManagementException("Policy attribute " + attribute.getName() - + " regex validation error.", - ExceptionCodes.INVALID_OPERATION_POLICY_PARAMETERS); + if (ServiceReferenceHolder.getInstance().isDetailedErrorResponsesEnabled()) { + ErrorHandler errorHandler = ExceptionCodes.from( + ExceptionCodes.INVALID_OPERATION_POLICY_PARAMS, attribute.getName()); + throw new APIManagementException( + "Invalid value provided for the operation policy parameter " + attribute.getName(), + errorHandler); + } else { + throw new APIManagementException( + "Policy attribute " + attribute.getName() + " regex validation error.", + ExceptionCodes.MISSING_OPERATION_POLICY_PARAMETERS); + } } } } else { @@ -1848,7 +1941,9 @@ private void validateAndSetAPISecurity(APIProduct apiProduct) { private void checkIfValidTransport(String transport) throws APIManagementException { if (!Constants.TRANSPORT_HTTP.equalsIgnoreCase(transport) && !Constants.TRANSPORT_HTTPS.equalsIgnoreCase(transport) && !APIConstants.WS_PROTOCOL.equalsIgnoreCase(transport) && !APIConstants.WSS_PROTOCOL.equalsIgnoreCase(transport)) { - handleException("Unsupported Transport [" + transport + ']'); + String errMsg = "Unsupported Transport [" + transport + ']'; + APIUtil.handleException(errMsg, ExceptionCodes + .from(ExceptionCodes.UNSUPPORTED_TRANSPORT, transport)); } } diff --git a/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/GlobalMediationPolicyImpl.java b/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/GlobalMediationPolicyImpl.java index 8f3ca7196ac2..78aa4ede1814 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/GlobalMediationPolicyImpl.java +++ b/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/GlobalMediationPolicyImpl.java @@ -8,6 +8,7 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.wso2.carbon.apimgt.api.APIManagementException; +import org.wso2.carbon.apimgt.api.ExceptionCodes; import org.wso2.carbon.apimgt.api.model.Mediation; import org.wso2.carbon.apimgt.api.model.policy.PolicyConstants; import org.wso2.carbon.apimgt.impl.internal.ServiceReferenceHolder; @@ -19,6 +20,7 @@ import org.wso2.carbon.registry.core.RegistryConstants; import org.wso2.carbon.registry.core.Resource; import org.wso2.carbon.registry.core.exceptions.RegistryException; +import org.wso2.carbon.registry.core.exceptions.ResourceNotFoundException; import org.wso2.carbon.user.api.UserStoreException; import javax.xml.namespace.QName; @@ -109,6 +111,14 @@ public List getAllGlobalMediationPolicies() throws APIManagementExcep } } } + } catch (ResourceNotFoundException e) { + if (ServiceReferenceHolder.getInstance().isDetailedErrorResponsesEnabled()) { + ExceptionCodes errorHandler = ExceptionCodes.GLOBAL_MEDIATION_POLICIES_NOT_FOUND; + throw new APIManagementException(errorHandler); + } else { + String msg = "Failed to get global mediation policies"; + throw new APIManagementException(msg, e); + } } catch (RegistryException e) { String msg = "Failed to get global mediation policies"; throw new APIManagementException(msg, e); 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 8cb0b9090952..a68ae3c76ba7 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 @@ -93,6 +93,7 @@ import org.wso2.carbon.apimgt.api.model.URITemplate; import org.wso2.carbon.apimgt.impl.APIConstants; import org.wso2.carbon.apimgt.impl.dao.ApiMgtDAO; +import org.wso2.carbon.apimgt.impl.internal.ServiceReferenceHolder; import org.wso2.carbon.apimgt.impl.utils.APIFileUtil; import org.wso2.carbon.apimgt.impl.utils.APIUtil; import org.wso2.carbon.registry.api.Registry; @@ -222,7 +223,13 @@ public static SwaggerVersion getSwaggerVersion(String apiDefinition) throws APIM return SwaggerVersion.SWAGGER; } - throw new APIManagementException("Invalid OAS definition provided."); + String errMsg = "Could not determine the OAS version as the version element of the definition is not found."; + if (ServiceReferenceHolder.getInstance().isDetailedErrorResponsesEnabled()) { + ExceptionCodes errorHandler = ExceptionCodes.OAS_DEFINITION_VERSION_NOT_FOUND; + throw new APIManagementException(errMsg, errorHandler); + } else { + throw new APIManagementException("Invalid OAS definition provided."); + } } public static Map generateExamples(String apiDefinition) throws APIManagementException { diff --git a/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/internal/APIManagerComponent.java b/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/internal/APIManagerComponent.java index 78ee7949bb27..9b9195fa059c 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/internal/APIManagerComponent.java +++ b/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/internal/APIManagerComponent.java @@ -348,6 +348,9 @@ protected void activate(ComponentContext componentContext) throws Exception { boolean isPolicyTableExists = ApiMgtDAO.getInstance().isTableExists("AM_API_POLICY_MAPPING"); boolean isAPIPoliciesEnabled = Boolean.parseBoolean(isAPIPoliciesEnabledConfig) && isPolicyTableExists; ServiceReferenceHolder.getInstance().setAPIPoliciesEnabled(isAPIPoliciesEnabled); + boolean isDetailedErrorResponsesEnabled = Boolean.parseBoolean(System.getProperty("detailedErrorResponses")); + + ServiceReferenceHolder.getInstance().setIsDetailedErrorResponses(isDetailedErrorResponsesEnabled); } catch (APIManagementException e) { log.error("Error while initializing the API manager component", e); diff --git a/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/internal/ServiceReferenceHolder.java b/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/internal/ServiceReferenceHolder.java index 5761e3c9b542..d1886abc4f85 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/internal/ServiceReferenceHolder.java +++ b/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/internal/ServiceReferenceHolder.java @@ -79,7 +79,7 @@ public class ServiceReferenceHolder { private Map apiDefinitionMap = new HashMap<>(); private WorkflowTaskService workflowTaskService; private boolean isAPIPoliciesEnabled = false; - + private boolean isDetailedErrorResponsesEnabled = false; private ServiceReferenceHolder() { } @@ -386,4 +386,13 @@ public boolean isAPIPoliciesEnabled() { public void setAPIPoliciesEnabled(boolean APIPoliciesEnabled) { isAPIPoliciesEnabled = APIPoliciesEnabled; } + + public void setIsDetailedErrorResponses(boolean isDetailedErrorResponsesEnabled) { + this.isDetailedErrorResponsesEnabled = isDetailedErrorResponsesEnabled; + } + + public boolean isDetailedErrorResponsesEnabled() { + return isDetailedErrorResponsesEnabled; + } + } diff --git a/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/utils/APIUtil.java b/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/utils/APIUtil.java index 278f026d8fc8..7652ea305fb9 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/utils/APIUtil.java +++ b/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/utils/APIUtil.java @@ -87,6 +87,7 @@ import org.wso2.carbon.apimgt.api.NewPostLoginExecutor; import org.wso2.carbon.apimgt.api.OrganizationResolver; import org.wso2.carbon.apimgt.api.PasswordResolver; +import org.wso2.carbon.apimgt.api.ErrorHandler; import org.wso2.carbon.apimgt.api.doc.model.APIDefinition; import org.wso2.carbon.apimgt.api.doc.model.APIResource; import org.wso2.carbon.apimgt.api.doc.model.Operation; @@ -1669,6 +1670,15 @@ public static void handleException(String msg) throws APIManagementException { throw new APIManagementException(msg); } + public static void handleException(String msg, ErrorHandler errorHandler) throws APIManagementException { + if (ServiceReferenceHolder.getInstance().isDetailedErrorResponsesEnabled()) { + throw new APIManagementException(msg, errorHandler); + } else { + log.error(msg); + throw new APIManagementException(msg); + } + } + public static void handleException(String msg, Throwable t) throws APIManagementException { log.error(msg, t); @@ -2331,8 +2341,13 @@ public static boolean hasPermission(String userNameWithoutChange, String permiss boolean authorized = false; if (userNameWithoutChange == null) { - throw new APIManagementException("Attempt to execute privileged operation as" + - " the anonymous user"); + String errMsg = "Attempt to execute privileged operation as the anonymous user"; + if (ServiceReferenceHolder.getInstance().isDetailedErrorResponsesEnabled()) { + ExceptionCodes errorHandler = ExceptionCodes.ANONYMOUS_USER_NOT_PERMITTED; + throw new APIManagementException(errMsg, errorHandler); + } else { + throw new APIManagementException("Attempt to execute privileged operation as the anonymous user"); + } } if (isPermissionCheckDisabled()) { @@ -2425,8 +2440,13 @@ public static LoggedUserInfo getLoggedInUserInfo(String cookie, String serviceUr public static String[] getListOfRoles(String username) throws APIManagementException { if (username == null) { - throw new APIManagementException("Attempt to execute privileged operation as" + - " the anonymous user"); + String errMsg = "Attempt to execute privileged operation as the anonymous user"; + if (ServiceReferenceHolder.getInstance().isDetailedErrorResponsesEnabled()) { + ExceptionCodes errorHandler = ExceptionCodes.ANONYMOUS_USER_NOT_PERMITTED; + throw new APIManagementException(errMsg, errorHandler); + } else { + throw new APIManagementException(errMsg); + } } String[] roles = getValueFromCache(APIConstants.API_USER_ROLE_CACHE, username); 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 c710e514a8b8..ac3eb9984db9 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 @@ -10745,6 +10745,9 @@ components: APIOperations: title: Operation type: object + required: + - target + - verb properties: id: 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/APIOperationsDTO.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/APIOperationsDTO.java index ea814ec2c6c3..94e532c5e542 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/APIOperationsDTO.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/APIOperationsDTO.java @@ -61,8 +61,9 @@ public APIOperationsDTO target(String target) { } - @ApiModelProperty(example = "/order/{orderId}", value = "") + @ApiModelProperty(example = "/order/{orderId}", required = true, value = "") @JsonProperty("target") + @NotNull public String getTarget() { return target; } @@ -78,8 +79,9 @@ public APIOperationsDTO verb(String verb) { } - @ApiModelProperty(example = "POST", value = "") + @ApiModelProperty(example = "POST", required = true, value = "") @JsonProperty("verb") + @NotNull public String getVerb() { return verb; } 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/APIMappingUtil.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/APIMappingUtil.java index 8adc606b657a..bc0701232f4f 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/APIMappingUtil.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/APIMappingUtil.java @@ -404,7 +404,13 @@ public static API fromDTOtoAPI(APIDTO dto, String provider) throws APIManagement } else if (dto.getKeyManagers() == null) { model.setKeyManagers(Collections.singletonList(APIConstants.KeyManager.API_LEVEL_ALL_KEY_MANAGERS)); } else { - throw new APIManagementException("KeyManagers value need to be an array"); + String errMsg = "KeyManagers value needs to be an array"; + if (ServiceReferenceHolder.getInstance().isDetailedErrorResponsesEnabled()) { + ExceptionCodes errorHandler = ExceptionCodes.KEYMANAGERS_VALUE_NOT_ARRAY; + throw new APIManagementException(errMsg, errorHandler); + } else { + throw new APIManagementException("KeyManagers value needs to be an array"); + } } APIServiceInfoDTO serviceInfoDTO = dto.getServiceInfo(); @@ -1713,23 +1719,33 @@ public static Set getURITemplates(API model, List } uriTemplates.add(template); } else { + final String errorMessageEndClause = " operation Type '" + httpVerb + "' provided" + " for operation" + + " '" + uriTempVal + "' is invalid"; if (APIConstants.GRAPHQL_API.equals(model.getType())) { - handleException( - "The GRAPHQL operation Type '" + httpVerb + "' provided for operation '" + uriTempVal - + "' is invalid"); + String errMsg = "The " + APIConstants.GRAPHQL_API + errorMessageEndClause; + ErrorHandler errorHandler = ExceptionCodes.from(ExceptionCodes.OPERATION_TYPE_INVALID, + APIConstants.GRAPHQL_API, httpVerb, uriTempVal); + APIUtil.handleException(errMsg, errorHandler); } else if (APIConstants.API_TYPE_WEBSUB.equals(model.getType())) { - handleException("The WEBSUB operation Type '" + httpVerb + "' provided for operation '" + uriTempVal - + "' is invalid"); + String errMsg = "The " + APIConstants.API_TYPE_WEBSUB + errorMessageEndClause; + ErrorHandler errorHandler = ExceptionCodes.from(ExceptionCodes.OPERATION_TYPE_INVALID, + APIConstants.API_TYPE_WEBSUB, httpVerb, uriTempVal); + APIUtil.handleException(errMsg, errorHandler); } else if (APIConstants.API_TYPE_SSE.equals(model.getType())) { - handleException("The SSE operation Type '" + httpVerb + "' provided for operation '" + uriTempVal - + "' is invalid"); + String errMsg = "The " + APIConstants.API_TYPE_SSE + errorMessageEndClause; + ErrorHandler errorHandler = ExceptionCodes.from(ExceptionCodes.OPERATION_TYPE_INVALID, + APIConstants.API_TYPE_SSE, httpVerb, uriTempVal); + APIUtil.handleException(errMsg, errorHandler); } else if (APIConstants.API_TYPE_WS.equals(model.getType())) { - handleException( - "The WEBSOCKET operation Type '" + httpVerb + "' provided for operation '" + uriTempVal - + "' is invalid"); + String errMsg = "The " + APIConstants.API_TYPE_WS + errorMessageEndClause; + ErrorHandler errorHandler = ExceptionCodes.from(ExceptionCodes.OPERATION_TYPE_INVALID, + APIConstants.API_TYPE_WS, httpVerb, uriTempVal); + APIUtil.handleException(errMsg, errorHandler); } else { - handleException("The HTTP method '" + httpVerb + "' provided for resource '" + uriTempVal - + "' is invalid"); + String errMsg = "The HTTP method '" + httpVerb + "' provided for resource '" + uriTempVal + "' is" + + " invalid"; + APIUtil.handleException(errMsg, + ExceptionCodes.from(ExceptionCodes.HTTP_METHOD_INVALID, httpVerb, uriTempVal)); } } @@ -3081,8 +3097,8 @@ private static JSONObject handleEndpointSecurity(API api, JSONObject endpointSec (JSONObject) endpointSecurityElement.get(APIConstants.ENDPOINT_SECURITY_SANDBOX); if (sandboxEndpointSecurity.get(APIConstants.ENDPOINT_SECURITY_PASSWORD) != null) { sandboxEndpointSecurity.put(APIConstants.ENDPOINT_SECURITY_PASSWORD, EMPTY_STRING); - if (sandboxEndpointSecurity.get(APIConstants.ENDPOINT_SECURITY_TYPE) - .equals(APIConstants.ENDPOINT_SECURITY_TYPE_OAUTH)) { + if (APIConstants.ENDPOINT_SECURITY_TYPE_OAUTH.equals( + sandboxEndpointSecurity.get(APIConstants.ENDPOINT_SECURITY_TYPE))) { sandboxEndpointSecurity.put(APIConstants.ENDPOINT_SECURITY_CLIENT_ID, EMPTY_STRING); sandboxEndpointSecurity.put(APIConstants.ENDPOINT_SECURITY_CLIENT_SECRET, EMPTY_STRING); } @@ -3093,8 +3109,8 @@ private static JSONObject handleEndpointSecurity(API api, JSONObject endpointSec (JSONObject) endpointSecurityElement.get(APIConstants.ENDPOINT_SECURITY_PRODUCTION); if (productionEndpointSecurity.get(APIConstants.ENDPOINT_SECURITY_PASSWORD) != null) { productionEndpointSecurity.put(APIConstants.ENDPOINT_SECURITY_PASSWORD, EMPTY_STRING); - if (productionEndpointSecurity.get(APIConstants.ENDPOINT_SECURITY_TYPE) - .equals(APIConstants.ENDPOINT_SECURITY_TYPE_OAUTH)) { + if (APIConstants.ENDPOINT_SECURITY_TYPE_OAUTH.equals( + productionEndpointSecurity.get(APIConstants.ENDPOINT_SECURITY_TYPE))) { productionEndpointSecurity.put(APIConstants.ENDPOINT_SECURITY_CLIENT_ID, EMPTY_STRING); productionEndpointSecurity.put(APIConstants.ENDPOINT_SECURITY_CLIENT_SECRET, EMPTY_STRING); } 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 6ecf519cd501..49a1ed11242d 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 @@ -1036,7 +1036,7 @@ public static OperationPolicyDataDTO importPolicy(String pathToArchive, String o policySpecification = getOperationPolicySpecificationFromFile(pathToArchive, fileName); if (policySpecification == null) { throw new APIManagementException("Policy Specification Cannot be null", - ExceptionCodes.INVALID_OPERATION_POLICY_PARAMETERS); + ExceptionCodes.MISSING_OPERATION_POLICY_PARAMETERS); } OperationPolicyData operationPolicyData = new OperationPolicyData(); operationPolicyData.setOrganization(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/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 cc22a078c7e2..8a2ed456a73c 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 @@ -38,6 +38,7 @@ import org.wso2.carbon.apimgt.api.APIDefinitionValidationResponse; import org.wso2.carbon.apimgt.api.APIManagementException; import org.wso2.carbon.apimgt.api.APIProvider; +import org.wso2.carbon.apimgt.api.ErrorHandler; import org.wso2.carbon.apimgt.api.ExceptionCodes; import org.wso2.carbon.apimgt.api.FaultGatewaysException; import org.wso2.carbon.apimgt.api.doc.model.APIResource; @@ -67,6 +68,7 @@ import org.wso2.carbon.apimgt.impl.definitions.OAS2Parser; import org.wso2.carbon.apimgt.impl.definitions.OAS3Parser; import org.wso2.carbon.apimgt.impl.definitions.OASParserUtil; +import org.wso2.carbon.apimgt.impl.internal.ServiceReferenceHolder; import org.wso2.carbon.apimgt.impl.utils.APIUtil; import org.wso2.carbon.apimgt.impl.utils.APIVersionStringComparator; import org.wso2.carbon.apimgt.impl.wsdl.SequenceGenerator; @@ -748,6 +750,9 @@ public static String validateAdditionalProperties(List endpoints = new ArrayList<>(); org.json.JSONObject endpointConfiguration = new org.json.JSONObject((Map) apiDto.getEndpointConfig()); @@ -1009,6 +1014,7 @@ public static boolean validateEndpoints(APIDTO apiDto) { return APIUtil.validateEndpointURLs(endpoints); } + /** * Extract sandbox or production endpoint URLs from endpoint config object. * @@ -1017,11 +1023,25 @@ public static boolean validateEndpoints(APIDTO apiDto) { * @param endpoints List of URLs. Extracted URL(s), if any, are added to this list. */ private static void extractURLsFromEndpointConfig(org.json.JSONObject endpointConfigObj, String endpointType, - ArrayList endpoints) { + ArrayList endpoints) throws APIManagementException { if (!endpointConfigObj.isNull(endpointType)) { org.json.JSONObject endpointObj = endpointConfigObj.optJSONObject(endpointType); if (endpointObj != null) { - endpoints.add(endpointConfigObj.getJSONObject(endpointType).getString(APIConstants.API_DATA_URL)); + if (ServiceReferenceHolder.getInstance().isDetailedErrorResponsesEnabled()) { + if (endpointObj.has(APIConstants.API_DATA_URL)) { + endpoints.add( + endpointConfigObj.getJSONObject(endpointType).getString(APIConstants.API_DATA_URL)); + } else { + ErrorHandler errorHandler = ExceptionCodes.from(ExceptionCodes.ENDPOINT_URL_NOT_PROVIDED, + endpointType); + throw new APIManagementException( + "Url is not provided for the endpoint type: " + endpointType + " in the endpoint " + + "config", + errorHandler); + } + } else { + endpoints.add(endpointConfigObj.getJSONObject(endpointType).getString(APIConstants.API_DATA_URL)); + } } else { JSONArray endpointArray = endpointConfigObj.getJSONArray(endpointType); for (int i = 0; i < endpointArray.length(); i++) { @@ -1113,6 +1133,7 @@ public static APIDTO.TypeEnum getAPIType(ServiceEntry.DefinitionType definitionT * @return API object to be created * @throws APIManagementException Error while creating the API */ + // 4 public static API prepareToCreateAPIByDTO(APIDTO body, APIProvider apiProvider, String username, String organization) throws APIManagementException { @@ -1265,7 +1286,13 @@ public static API prepareToCreateAPIByDTO(APIDTO body, APIProvider apiProvider, } else if (body.getKeyManagers() == null) { apiToAdd.setKeyManagers(Collections.singletonList(APIConstants.KeyManager.API_LEVEL_ALL_KEY_MANAGERS)); } else { - throw new APIManagementException("KeyManagers value need to be an array"); + String errMsg = "KeyManagers value needs to be an array"; + if (ServiceReferenceHolder.getInstance().isDetailedErrorResponsesEnabled()) { + ExceptionCodes errorHandler = ExceptionCodes.KEYMANAGERS_VALUE_NOT_ARRAY; + throw new APIManagementException(errMsg, errorHandler); + } else { + throw new APIManagementException("KeyManagers value needs to be an array"); + } } // Set default gatewayVendor 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 b9f488b54c0d..1c5460d4bcf6 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 @@ -31,6 +31,7 @@ import org.apache.cxf.jaxrs.ext.multipart.Attachment; import org.apache.cxf.jaxrs.ext.multipart.ContentDisposition; import org.apache.cxf.phase.PhaseInterceptorChain; +import org.apache.http.HttpStatus; import org.json.simple.JSONObject; import org.json.simple.parser.JSONParser; import org.json.simple.parser.ParseException; @@ -55,6 +56,7 @@ import org.wso2.carbon.apimgt.impl.importexport.ImportExportAPI; import org.wso2.carbon.apimgt.impl.importexport.utils.APIImportExportUtil; import org.wso2.carbon.apimgt.impl.importexport.utils.CommonUtil; +import org.wso2.carbon.apimgt.impl.internal.ServiceReferenceHolder; import org.wso2.carbon.apimgt.impl.restapi.CommonUtils; import org.wso2.carbon.apimgt.impl.restapi.publisher.ApisApiServiceImplUtils; import org.wso2.carbon.apimgt.impl.restapi.publisher.OperationPoliciesApiServiceImplUtils; @@ -635,7 +637,8 @@ public Response updateAPIGraphQLSchema(String apiId, String schemaDefinition, St } @Override - public Response updateAPI(String apiId, APIDTO body, String ifMatch, MessageContext messageContext) { + public Response updateAPI(String apiId, APIDTO body, String ifMatch, MessageContext messageContext) + throws APIManagementException { String[] tokenScopes = (String[]) PhaseInterceptorChain.getCurrentMessage().getExchange() .get(RestApiConstants.USER_REST_API_SCOPES); @@ -670,12 +673,18 @@ public Response updateAPI(String apiId, APIDTO body, String ifMatch, MessageCont //Auth failure occurs when cross tenant accessing APIs. Sends 404, since we don't need // to expose the existence of the resource if (RestApiUtil.isDueToResourceNotFound(e) || RestApiUtil.isDueToAuthorizationFailure(e)) { - RestApiUtil.handleResourceNotFoundError(RestApiConstants.RESOURCE_API, apiId, e, log); + if (ServiceReferenceHolder.getInstance().isDetailedErrorResponsesEnabled() && e.getErrorHandler() + .getErrorCode() == ExceptionCodes.GLOBAL_MEDIATION_POLICIES_NOT_FOUND.getErrorCode()) { + RestApiUtil.handleResourceNotFoundError(e.getErrorHandler().getErrorDescription(), e, log); + } else { + RestApiUtil.handleResourceNotFoundError(RestApiConstants.RESOURCE_API, apiId, e, log); + } } else if (isAuthorizationFailure(e)) { RestApiUtil.handleAuthorizationFailure("Authorization failure while updating API : " + apiId, e, log); - } else if (e.getErrorHandler().getErrorCode() == ExceptionCodes.USER_ROLES_CANNOT_BE_NULL.getErrorCode()) { - RestApiUtil.handleBadRequest("Bad Request while updating API : " + apiId, e, log); } else { + if ((ServiceReferenceHolder.getInstance().isDetailedErrorResponsesEnabled())) { + throw e; + } String errorMessage = "Error while updating the API : " + apiId + " - " + e.getMessage(); RestApiUtil.handleInternalServerError(errorMessage, e, log); } 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 c710e514a8b8..ac3eb9984db9 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 @@ -10745,6 +10745,9 @@ components: APIOperations: title: Operation type: object + required: + - target + - verb properties: id: type: string From 97280d0cae6483d3664f2013a586b39ff38238ef Mon Sep 17 00:00:00 2001 From: rmsamitha Date: Fri, 28 Jun 2024 16:26:44 +0530 Subject: [PATCH 2/2] Handling httpVerb and target related error scenarios --- .../wso2/carbon/apimgt/api/ExceptionCodes.java | 9 ++++++++- .../v1/common/mappings/APIMappingUtil.java | 15 +++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) 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 d34eda302d86..cc28953d59ee 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 @@ -594,7 +594,14 @@ public enum ExceptionCodes implements ErrorHandler { "Invalid values provided for %s endpoint security configuration", false), ENDPOINT_SECURITY_TYPE_NOT_DEFINED(903214, "Endpoint security type not defined", 400, - "Endpoint security type not defined for the %s endpoint", false); + "Endpoint security type not defined for the %s endpoint", false), + + 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"), + + RESOURCE_URI_TEMPLATE_NOT_DEFINED(902032, "Resource URI template value not defined", 400, + "Resource URI template value (target) not defined", false); private final long errorCode; private final String errorMessage; 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/APIMappingUtil.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/APIMappingUtil.java index bc0701232f4f..b9594a9892cb 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/APIMappingUtil.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/APIMappingUtil.java @@ -1668,6 +1668,13 @@ public static Set getURITemplates(API model, List String uriTempVal = operation.getTarget(); + if (ServiceReferenceHolder.getInstance().isDetailedErrorResponsesEnabled()) { + if (StringUtils.isEmpty(uriTempVal)) { + String errMsg = "Resource URI template value (target) is not specified for the operation/resource"; + handleException(errMsg, ExceptionCodes.RESOURCE_URI_TEMPLATE_NOT_DEFINED); + } + } + String httpVerb = operation.getVerb(); List scopeList = operation.getScopes(); if (scopeList != null) { @@ -1687,6 +1694,14 @@ public static Set getURITemplates(API model, List if (amznResourceName != null) { template.setAmznResourceName(amznResourceName); } + + if (StringUtils.isEmpty(httpVerb)) { + String errMsg = "Operation type/http method is not specified for the operation/resource " + uriTempVal; + handleException(errMsg, + ExceptionCodes.from(ExceptionCodes.OPERATION_OR_RESOURCE_TYPE_OR_METHOD_NOT_DEFINED, + uriTempVal)); + } + //Only continue for supported operations if (APIConstants.SUPPORTED_METHODS.contains(httpVerb.toLowerCase()) || (APIConstants.GRAPHQL_SUPPORTED_METHOD_LIST.contains(httpVerb.toUpperCase()))