implemented validators endpoints (#4309)
This commit is contained in:
		
							parent
							
								
									d56a3989eb
								
							
						
					
					
						commit
						f7d490167b
					
				@ -192,6 +192,15 @@ class RestAPINotFound(NotFoundException):
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class RequestValidatorNotFound(BadRequestException):
 | 
			
		||||
    code = 400
 | 
			
		||||
 | 
			
		||||
    def __init__(self):
 | 
			
		||||
        super(RequestValidatorNotFound, self).__init__(
 | 
			
		||||
            "NotFoundException", "Invalid Request Validator Id specified"
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ModelNotFound(NotFoundException):
 | 
			
		||||
    code = 404
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -17,7 +17,7 @@ except ImportError:
 | 
			
		||||
    from urllib.parse import urlparse
 | 
			
		||||
import responses
 | 
			
		||||
from moto.core import ACCOUNT_ID, BaseBackend, BaseModel, CloudFormationModel
 | 
			
		||||
from .utils import create_id
 | 
			
		||||
from .utils import create_id, to_path
 | 
			
		||||
from moto.core.utils import path_url
 | 
			
		||||
from .exceptions import (
 | 
			
		||||
    ApiKeyNotFoundException,
 | 
			
		||||
@ -41,6 +41,7 @@ from .exceptions import (
 | 
			
		||||
    InvalidRestApiId,
 | 
			
		||||
    InvalidModelName,
 | 
			
		||||
    RestAPINotFound,
 | 
			
		||||
    RequestValidatorNotFound,
 | 
			
		||||
    ModelNotFound,
 | 
			
		||||
    ApiKeyValueMinLength,
 | 
			
		||||
)
 | 
			
		||||
@ -652,6 +653,52 @@ class UsagePlan(BaseModel, dict):
 | 
			
		||||
                    self["throttle"]["burstLimit"] = value
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class RequestValidator(BaseModel, dict):
 | 
			
		||||
    PROP_ID = "id"
 | 
			
		||||
    PROP_NAME = "name"
 | 
			
		||||
    PROP_VALIDATE_REQUEST_BODY = "validateRequestBody"
 | 
			
		||||
    PROP_VALIDATE_REQUEST_PARAMETERS = "validateRequestParameters"
 | 
			
		||||
 | 
			
		||||
    # operations
 | 
			
		||||
    OP_PATH = "path"
 | 
			
		||||
    OP_VALUE = "value"
 | 
			
		||||
    OP_REPLACE = "replace"
 | 
			
		||||
    OP_OP = "op"
 | 
			
		||||
 | 
			
		||||
    def __init__(self, id, name, validateRequestBody, validateRequestParameters):
 | 
			
		||||
        super(RequestValidator, self).__init__()
 | 
			
		||||
        self[RequestValidator.PROP_ID] = id
 | 
			
		||||
        self[RequestValidator.PROP_NAME] = name
 | 
			
		||||
        self[RequestValidator.PROP_VALIDATE_REQUEST_BODY] = validateRequestBody
 | 
			
		||||
        self[
 | 
			
		||||
            RequestValidator.PROP_VALIDATE_REQUEST_PARAMETERS
 | 
			
		||||
        ] = validateRequestParameters
 | 
			
		||||
 | 
			
		||||
    def apply_patch_operations(self, operations):
 | 
			
		||||
        for operation in operations:
 | 
			
		||||
            path = operation[RequestValidator.OP_PATH]
 | 
			
		||||
            value = operation[RequestValidator.OP_VALUE]
 | 
			
		||||
            if operation[RequestValidator.OP_OP] == RequestValidator.OP_REPLACE:
 | 
			
		||||
                if to_path(RequestValidator.PROP_NAME) in path:
 | 
			
		||||
                    self[RequestValidator.PROP_NAME] = value
 | 
			
		||||
                if to_path(RequestValidator.PROP_VALIDATE_REQUEST_BODY) in path:
 | 
			
		||||
                    self[
 | 
			
		||||
                        RequestValidator.PROP_VALIDATE_REQUEST_BODY
 | 
			
		||||
                    ] = value.lower() in ("true")
 | 
			
		||||
                if to_path(RequestValidator.PROP_VALIDATE_REQUEST_PARAMETERS) in path:
 | 
			
		||||
                    self[
 | 
			
		||||
                        RequestValidator.PROP_VALIDATE_REQUEST_PARAMETERS
 | 
			
		||||
                    ] = value.lower() in ("true")
 | 
			
		||||
 | 
			
		||||
    def to_dict(self):
 | 
			
		||||
        return {
 | 
			
		||||
            "id": self["id"],
 | 
			
		||||
            "name": self["name"],
 | 
			
		||||
            "validateRequestBody": self["validateRequestBody"],
 | 
			
		||||
            "validateRequestParameters": self["validateRequestParameters"],
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class UsagePlanKey(BaseModel, dict):
 | 
			
		||||
    def __init__(self, id, type, name, value):
 | 
			
		||||
        super(UsagePlanKey, self).__init__()
 | 
			
		||||
@ -708,6 +755,7 @@ class RestAPI(CloudFormationModel):
 | 
			
		||||
        self.stages = {}
 | 
			
		||||
        self.resources = {}
 | 
			
		||||
        self.models = {}
 | 
			
		||||
        self.request_validators = {}
 | 
			
		||||
        self.add_child("/")  # Add default child
 | 
			
		||||
 | 
			
		||||
    def __repr__(self):
 | 
			
		||||
@ -948,6 +996,36 @@ class RestAPI(CloudFormationModel):
 | 
			
		||||
    def delete_deployment(self, deployment_id):
 | 
			
		||||
        return self.deployments.pop(deployment_id)
 | 
			
		||||
 | 
			
		||||
    def create_request_validator(
 | 
			
		||||
        self, name, validateRequestBody, validateRequestParameters
 | 
			
		||||
    ):
 | 
			
		||||
        validator_id = create_id()
 | 
			
		||||
        request_validator = RequestValidator(
 | 
			
		||||
            id=validator_id,
 | 
			
		||||
            name=name,
 | 
			
		||||
            validateRequestBody=validateRequestBody,
 | 
			
		||||
            validateRequestParameters=validateRequestParameters,
 | 
			
		||||
        )
 | 
			
		||||
        self.request_validators[validator_id] = request_validator
 | 
			
		||||
        return request_validator
 | 
			
		||||
 | 
			
		||||
    def get_request_validators(self):
 | 
			
		||||
        return list(self.request_validators.values())
 | 
			
		||||
 | 
			
		||||
    def get_request_validator(self, validator_id):
 | 
			
		||||
        reqeust_validator = self.request_validators.get(validator_id)
 | 
			
		||||
        if reqeust_validator is None:
 | 
			
		||||
            raise RequestValidatorNotFound()
 | 
			
		||||
        return reqeust_validator
 | 
			
		||||
 | 
			
		||||
    def delete_request_validator(self, validator_id):
 | 
			
		||||
        reqeust_validator = self.request_validators.pop(validator_id)
 | 
			
		||||
        return reqeust_validator
 | 
			
		||||
 | 
			
		||||
    def update_request_validator(self, validator_id, patch_operations):
 | 
			
		||||
        self.request_validators[validator_id].apply_patch_operations(patch_operations)
 | 
			
		||||
        return self.request_validators[validator_id]
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class DomainName(BaseModel, dict):
 | 
			
		||||
    def __init__(self, domain_name, **kwargs):
 | 
			
		||||
 | 
			
		||||
@ -306,6 +306,58 @@ class APIGatewayResponse(BaseResponse):
 | 
			
		||||
 | 
			
		||||
        return 200, {}, json.dumps(authorizer_response)
 | 
			
		||||
 | 
			
		||||
    def request_validators(self, request, full_url, headers):
 | 
			
		||||
        self.setup_class(request, full_url, headers)
 | 
			
		||||
        url_path_parts = self.path.split("/")
 | 
			
		||||
        restapi_id = url_path_parts[2]
 | 
			
		||||
        try:
 | 
			
		||||
            restApi = self.backend.get_rest_api(restapi_id)
 | 
			
		||||
            if self.method == "GET":
 | 
			
		||||
                validators = restApi.get_request_validators()
 | 
			
		||||
                res = json.dumps(
 | 
			
		||||
                    {"item": [validator.to_dict() for validator in validators]}
 | 
			
		||||
                )
 | 
			
		||||
                return 200, {}, res
 | 
			
		||||
            if self.method == "POST":
 | 
			
		||||
                name = self._get_param("name")
 | 
			
		||||
                validateRequestBody = self._get_bool_param("validateRequestBody")
 | 
			
		||||
                validateRequestParameters = self._get_bool_param(
 | 
			
		||||
                    "validateRequestParameters"
 | 
			
		||||
                )
 | 
			
		||||
                validator = restApi.create_request_validator(
 | 
			
		||||
                    name=name,
 | 
			
		||||
                    validateRequestBody=validateRequestBody,
 | 
			
		||||
                    validateRequestParameters=validateRequestParameters,
 | 
			
		||||
                )
 | 
			
		||||
                return 200, {}, json.dumps(validator)
 | 
			
		||||
        except BadRequestException as e:
 | 
			
		||||
            return self.error("BadRequestException", e.message)
 | 
			
		||||
        except CrossAccountNotAllowed as e:
 | 
			
		||||
            return self.error("AccessDeniedException", e.message)
 | 
			
		||||
 | 
			
		||||
    def request_validator_individual(self, request, full_url, headers):
 | 
			
		||||
        self.setup_class(request, full_url, headers)
 | 
			
		||||
        url_path_parts = self.path.split("/")
 | 
			
		||||
        restapi_id = url_path_parts[2]
 | 
			
		||||
        validator_id = url_path_parts[4]
 | 
			
		||||
        try:
 | 
			
		||||
            restApi = self.backend.get_rest_api(restapi_id)
 | 
			
		||||
            if self.method == "GET":
 | 
			
		||||
                return 200, {}, json.dumps(restApi.get_request_validator(validator_id))
 | 
			
		||||
            if self.method == "DELETE":
 | 
			
		||||
                restApi.delete_request_validator(validator_id)
 | 
			
		||||
                return 202, {}, ""
 | 
			
		||||
            if self.method == "PATCH":
 | 
			
		||||
                patch_operations = self._get_param("patchOperations")
 | 
			
		||||
                validator = restApi.update_request_validator(
 | 
			
		||||
                    validator_id, patch_operations
 | 
			
		||||
                )
 | 
			
		||||
                return 200, {}, json.dumps(validator)
 | 
			
		||||
        except BadRequestException as e:
 | 
			
		||||
            return self.error("BadRequestException", e.message)
 | 
			
		||||
        except CrossAccountNotAllowed as e:
 | 
			
		||||
            return self.error("AccessDeniedException", e.message)
 | 
			
		||||
 | 
			
		||||
    def authorizers(self, request, full_url, headers):
 | 
			
		||||
        self.setup_class(request, full_url, headers)
 | 
			
		||||
        url_path_parts = self.path.split("/")
 | 
			
		||||
 | 
			
		||||
@ -31,4 +31,6 @@ url_paths = {
 | 
			
		||||
    "{0}/usageplans/(?P<usage_plan_id>[^/]+)/?$": response.usage_plan_individual,
 | 
			
		||||
    "{0}/usageplans/(?P<usage_plan_id>[^/]+)/keys$": response.usage_plan_keys,
 | 
			
		||||
    "{0}/usageplans/(?P<usage_plan_id>[^/]+)/keys/(?P<api_key_id>[^/]+)/?$": response.usage_plan_key_individual,
 | 
			
		||||
    "{0}/restapis/(?P<function_id>[^/]+)/requestvalidators$": response.request_validators,
 | 
			
		||||
    "{0}/restapis/(?P<api_id>[^/]+)/requestvalidators/(?P<validator_id>[^/]+)/?$": response.request_validator_individual,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -7,3 +7,7 @@ def create_id():
 | 
			
		||||
    size = 10
 | 
			
		||||
    chars = list(range(10)) + list(string.ascii_lowercase)
 | 
			
		||||
    return "".join(str(random.choice(chars)) for x in range(size))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def to_path(prop):
 | 
			
		||||
    return "/" + prop
 | 
			
		||||
 | 
			
		||||
@ -375,7 +375,6 @@ class BotocoreStubber:
 | 
			
		||||
    def __call__(self, event_name, request, **kwargs):
 | 
			
		||||
        if not self.enabled:
 | 
			
		||||
            return None
 | 
			
		||||
 | 
			
		||||
        response = None
 | 
			
		||||
        response_callback = None
 | 
			
		||||
        found_index = None
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										170
									
								
								tests/test_apigateway/test_apigateway_validators.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										170
									
								
								tests/test_apigateway/test_apigateway_validators.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,170 @@
 | 
			
		||||
import boto3
 | 
			
		||||
import sure  # noqa
 | 
			
		||||
from moto import mock_apigateway
 | 
			
		||||
from moto.apigateway.exceptions import RequestValidatorNotFound
 | 
			
		||||
from botocore.exceptions import ClientError
 | 
			
		||||
import pytest
 | 
			
		||||
 | 
			
		||||
ID = "id"
 | 
			
		||||
NAME = "name"
 | 
			
		||||
VALIDATE_REQUEST_BODY = "validateRequestBody"
 | 
			
		||||
VALIDATE_REQUEST_PARAMETERS = "validateRequestParameters"
 | 
			
		||||
PARAM_NAME = "my-validator"
 | 
			
		||||
RESPONSE_METADATA = "ResponseMetadata"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@mock_apigateway
 | 
			
		||||
def test_create_request_validator():
 | 
			
		||||
    client = create_client()
 | 
			
		||||
    api_id = create_rest_api_id(client)
 | 
			
		||||
    response = create_validator(client, api_id)
 | 
			
		||||
    response.pop(RESPONSE_METADATA)
 | 
			
		||||
    response.pop(ID)
 | 
			
		||||
    response.should.equal(
 | 
			
		||||
        {
 | 
			
		||||
            NAME: PARAM_NAME,
 | 
			
		||||
            VALIDATE_REQUEST_BODY: True,
 | 
			
		||||
            VALIDATE_REQUEST_PARAMETERS: True,
 | 
			
		||||
        }
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@mock_apigateway
 | 
			
		||||
def test_get_request_validators():
 | 
			
		||||
 | 
			
		||||
    client = create_client()
 | 
			
		||||
    api_id = create_rest_api_id(client)
 | 
			
		||||
    response = client.get_request_validators(restApiId=api_id)
 | 
			
		||||
 | 
			
		||||
    validators = response["items"]
 | 
			
		||||
    validators.should.have.length_of(0)
 | 
			
		||||
 | 
			
		||||
    response.pop(RESPONSE_METADATA)
 | 
			
		||||
    response.should.equal({"items": []})
 | 
			
		||||
 | 
			
		||||
    response = create_validator(client, api_id)
 | 
			
		||||
    validator_id1 = response[ID]
 | 
			
		||||
    response = create_validator(client, api_id)
 | 
			
		||||
    validator_id2 = response[ID]
 | 
			
		||||
    response = client.get_request_validators(restApiId=api_id)
 | 
			
		||||
 | 
			
		||||
    validators = response["items"]
 | 
			
		||||
    validators.should.have.length_of(2)
 | 
			
		||||
 | 
			
		||||
    response.pop(RESPONSE_METADATA)
 | 
			
		||||
    response.should.equal(
 | 
			
		||||
        {
 | 
			
		||||
            "items": [
 | 
			
		||||
                {
 | 
			
		||||
                    ID: validator_id1,
 | 
			
		||||
                    NAME: PARAM_NAME,
 | 
			
		||||
                    VALIDATE_REQUEST_BODY: True,
 | 
			
		||||
                    VALIDATE_REQUEST_PARAMETERS: True,
 | 
			
		||||
                },
 | 
			
		||||
                {
 | 
			
		||||
                    ID: validator_id2,
 | 
			
		||||
                    NAME: PARAM_NAME,
 | 
			
		||||
                    VALIDATE_REQUEST_BODY: True,
 | 
			
		||||
                    VALIDATE_REQUEST_PARAMETERS: True,
 | 
			
		||||
                },
 | 
			
		||||
            ]
 | 
			
		||||
        }
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@mock_apigateway
 | 
			
		||||
def test_get_request_validator():
 | 
			
		||||
    client = create_client()
 | 
			
		||||
    api_id = create_rest_api_id(client)
 | 
			
		||||
    response = create_validator(client, api_id)
 | 
			
		||||
    validator_id = response[ID]
 | 
			
		||||
    response = client.get_request_validator(
 | 
			
		||||
        restApiId=api_id, requestValidatorId=validator_id
 | 
			
		||||
    )
 | 
			
		||||
    response.pop(RESPONSE_METADATA)
 | 
			
		||||
    response.should.equal(
 | 
			
		||||
        {
 | 
			
		||||
            ID: validator_id,
 | 
			
		||||
            NAME: PARAM_NAME,
 | 
			
		||||
            VALIDATE_REQUEST_BODY: True,
 | 
			
		||||
            VALIDATE_REQUEST_PARAMETERS: True,
 | 
			
		||||
        }
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@mock_apigateway
 | 
			
		||||
def test_delete_request_validator():
 | 
			
		||||
    client = create_client()
 | 
			
		||||
    api_id = create_rest_api_id(client)
 | 
			
		||||
    response = create_validator(client, api_id)
 | 
			
		||||
    # test get single validator by
 | 
			
		||||
    validator_id = response[ID]
 | 
			
		||||
    response = client.get_request_validator(
 | 
			
		||||
        restApiId=api_id, requestValidatorId=validator_id
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    response.pop(RESPONSE_METADATA)
 | 
			
		||||
    response.should.equal(
 | 
			
		||||
        {
 | 
			
		||||
            ID: validator_id,
 | 
			
		||||
            NAME: PARAM_NAME,
 | 
			
		||||
            VALIDATE_REQUEST_BODY: True,
 | 
			
		||||
            VALIDATE_REQUEST_PARAMETERS: True,
 | 
			
		||||
        }
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    # delete validator
 | 
			
		||||
    response = client.delete_request_validator(
 | 
			
		||||
        restApiId=api_id, requestValidatorId=validator_id
 | 
			
		||||
    )
 | 
			
		||||
    with pytest.raises(ClientError) as ex:
 | 
			
		||||
        client.get_request_validator(restApiId=api_id, requestValidatorId=validator_id)
 | 
			
		||||
    err = ex.value.response["Error"]
 | 
			
		||||
    err["Code"].should.equal("BadRequestException")
 | 
			
		||||
    err["Message"].should.equal("Invalid Request Validator Id specified")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@mock_apigateway
 | 
			
		||||
def test_update_request_validator():
 | 
			
		||||
    client = create_client()
 | 
			
		||||
    api_id = create_rest_api_id(client)
 | 
			
		||||
    response = create_validator(client, api_id)
 | 
			
		||||
 | 
			
		||||
    validator_id = response[ID]
 | 
			
		||||
    response = client.update_request_validator(
 | 
			
		||||
        restApiId=api_id,
 | 
			
		||||
        requestValidatorId=validator_id,
 | 
			
		||||
        patchOperations=[
 | 
			
		||||
            {"op": "replace", "path": "/name", "value": PARAM_NAME + PARAM_NAME},
 | 
			
		||||
            {"op": "replace", "path": "/validateRequestBody", "value": "False"},
 | 
			
		||||
            {"op": "replace", "path": "/validateRequestParameters", "value": "False"},
 | 
			
		||||
        ],
 | 
			
		||||
    )
 | 
			
		||||
    response.pop(RESPONSE_METADATA)
 | 
			
		||||
    response.should.equal(
 | 
			
		||||
        {
 | 
			
		||||
            ID: validator_id,
 | 
			
		||||
            NAME: PARAM_NAME + PARAM_NAME,
 | 
			
		||||
            VALIDATE_REQUEST_BODY: False,
 | 
			
		||||
            VALIDATE_REQUEST_PARAMETERS: False,
 | 
			
		||||
        }
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def create_validator(client, api_id):
 | 
			
		||||
    response = client.create_request_validator(
 | 
			
		||||
        restApiId=api_id,
 | 
			
		||||
        name=PARAM_NAME,
 | 
			
		||||
        validateRequestBody=True,
 | 
			
		||||
        validateRequestParameters=True,
 | 
			
		||||
    )
 | 
			
		||||
    return response
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def create_client():
 | 
			
		||||
    return boto3.client("apigateway", region_name="us-west-2")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def create_rest_api_id(client):
 | 
			
		||||
    response = client.create_rest_api(name="my_api", description="this is my api")
 | 
			
		||||
    return response[ID]
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user