From 95f9b3fb35018dfdf88d0d25fa8594ef265eea12 Mon Sep 17 00:00:00 2001 From: Steve Pulec Date: Sat, 5 Mar 2016 09:48:37 -0500 Subject: [PATCH] add integration responses. --- moto/apigateway/models.py | 42 +++++++- moto/apigateway/responses.py | 38 +++++-- moto/apigateway/urls.py | 1 + tests/test_apigateway/test_apigateway.py | 130 ++++++++++++++++++++++- 4 files changed, 194 insertions(+), 17 deletions(-) diff --git a/moto/apigateway/models.py b/moto/apigateway/models.py index e9f8e5470..4b9b1fdbf 100644 --- a/moto/apigateway/models.py +++ b/moto/apigateway/models.py @@ -13,11 +13,34 @@ class Deployment(dict): self['stageName'] = name +class IntegrationResponse(dict): + def __init__(self, status_code, selection_pattern=None): + self['responseTemplates'] = {"application/json": None} + self['statusCode'] = status_code + if selection_pattern: + self['selectionPattern'] = selection_pattern + + class Integration(dict): - def __init__(self, integration_type, uri): + def __init__(self, integration_type, uri, http_method): super(Integration, self).__init__() self['type'] = integration_type self['uri'] = uri + self['httpMethod'] = http_method + self["integrationResponses"] = { + "200": IntegrationResponse(200) + } + + def create_integration_response(self, status_code, selection_pattern): + integration_response = IntegrationResponse(status_code, selection_pattern) + self["integrationResponses"][status_code] = integration_response + return integration_response + + def get_integration_response(self, status_code): + return self["integrationResponses"][status_code] + + def delete_integration_response(self, status_code): + return self["integrationResponses"].pop(status_code) class MethodResponse(dict): @@ -80,7 +103,7 @@ class Resource(object): return self.resource_methods[method_type] def add_integration(self, method_type, integration_type, uri): - integration = Integration(integration_type, uri) + integration = Integration(integration_type, uri, method_type) self.resource_methods[method_type]['methodIntegration'] = integration return integration @@ -220,6 +243,21 @@ class APIGatewayBackend(BaseBackend): resource = self.get_resource(function_id, resource_id) return resource.delete_integration(method_type) + def create_integration_response(self, function_id, resource_id, method_type, status_code, selection_pattern): + integration = self.get_integration(function_id, resource_id, method_type) + integration_response = integration.create_integration_response(status_code, selection_pattern) + return integration_response + + def get_integration_response(self, function_id, resource_id, method_type, status_code): + integration = self.get_integration(function_id, resource_id, method_type) + integration_response = integration.get_integration_response(status_code) + return integration_response + + def delete_integration_response(self, function_id, resource_id, method_type, status_code): + integration = self.get_integration(function_id, resource_id, method_type) + integration_response = integration.delete_integration_response(status_code) + return integration_response + def create_deployment(self, function_id, name): api = self.get_rest_api(function_id) deployment = api.create_deployment(name) diff --git a/moto/apigateway/responses.py b/moto/apigateway/responses.py index cebd2c7dd..03776c9f4 100644 --- a/moto/apigateway/responses.py +++ b/moto/apigateway/responses.py @@ -57,14 +57,12 @@ class APIGatewayResponse(BaseResponse): if self.method == 'GET': resource = self.backend.get_resource(function_id, resource_id) - return 200, headers, json.dumps(resource.to_dict()) elif self.method == 'POST': path_part = self._get_param("pathPart") resource = self.backend.create_resource(function_id, resource_id, path_part) - return 200, headers, json.dumps(resource.to_dict()) elif self.method == 'DELETE': resource = self.backend.delete_resource(function_id, resource_id) - return 200, headers, json.dumps(resource.to_dict()) + return 200, headers, json.dumps(resource.to_dict()) def resource_methods(self, request, full_url, headers): self.setup_class(request, full_url, headers) @@ -91,13 +89,11 @@ class APIGatewayResponse(BaseResponse): if self.method == 'GET': method_response = self.backend.get_method_response(function_id, resource_id, method_type, response_code) - return 200, headers, json.dumps(method_response) elif self.method == 'PUT': method_response = self.backend.create_method_response(function_id, resource_id, method_type, response_code) - return 200, headers, json.dumps(method_response) elif self.method == 'DELETE': method_response = self.backend.delete_method_response(function_id, resource_id, method_type, response_code) - return 200, headers, json.dumps(method_response) + return 200, headers, json.dumps(method_response) def integrations(self, request, full_url, headers): self.setup_class(request, full_url, headers) @@ -108,15 +104,36 @@ class APIGatewayResponse(BaseResponse): if self.method == 'GET': integration_response = self.backend.get_integration(function_id, resource_id, method_type) - return 200, headers, json.dumps(integration_response) elif self.method == 'PUT': integration_type = self._get_param('type') uri = self._get_param('uri') integration_response = self.backend.create_integration(function_id, resource_id, method_type, integration_type, uri) - return 200, headers, json.dumps(integration_response) elif self.method == 'DELETE': integration_response = self.backend.delete_integration(function_id, resource_id, method_type) - return 200, headers, json.dumps(integration_response) + return 200, headers, json.dumps(integration_response) + + def integration_responses(self, request, full_url, headers): + self.setup_class(request, full_url, headers) + url_path_parts = self.path.split("/") + function_id = url_path_parts[2] + resource_id = url_path_parts[4] + method_type = url_path_parts[6] + status_code = url_path_parts[9] + + if self.method == 'GET': + integration_response = self.backend.get_integration_response( + function_id, resource_id, method_type, status_code + ) + elif self.method == 'PUT': + selection_pattern = self._get_param("selectionPattern") + integration_response = self.backend.create_integration_response( + function_id, resource_id, method_type, status_code, selection_pattern + ) + elif self.method == 'DELETE': + integration_response = self.backend.delete_integration_response( + function_id, resource_id, method_type, status_code + ) + return 200, headers, json.dumps(integration_response) def deployments(self, request, full_url, headers): self.setup_class(request, full_url, headers) @@ -138,7 +155,6 @@ class APIGatewayResponse(BaseResponse): if self.method == 'GET': deployment = self.backend.get_deployment(function_id, deployment_id) - return 200, headers, json.dumps(deployment) elif self.method == 'DELETE': deployment = self.backend.delete_deployment(function_id, deployment_id) - return 200, headers, json.dumps(deployment) + return 200, headers, json.dumps(deployment) diff --git a/moto/apigateway/urls.py b/moto/apigateway/urls.py index 731c01319..e34dbbe61 100644 --- a/moto/apigateway/urls.py +++ b/moto/apigateway/urls.py @@ -15,4 +15,5 @@ url_paths = { '{0}/restapis/(?P[^/]+)/resources/(?P[^/]+)/methods/(?P[^/]+)/?$': APIGatewayResponse().resource_methods, '{0}/restapis/(?P[^/]+)/resources/(?P[^/]+)/methods/(?P[^/]+)/responses/200$': APIGatewayResponse().resource_method_responses, '{0}/restapis/(?P[^/]+)/resources/(?P[^/]+)/methods/(?P[^/]+)/integration/?$': APIGatewayResponse().integrations, + '{0}/restapis/(?P[^/]+)/resources/(?P[^/]+)/methods/(?P[^/]+)/integration/responses/(?P\d+)/?$': APIGatewayResponse().integration_responses, } diff --git a/tests/test_apigateway/test_apigateway.py b/tests/test_apigateway/test_apigateway.py index e7ac11670..f5b31b20e 100644 --- a/tests/test_apigateway/test_apigateway.py +++ b/tests/test_apigateway/test_apigateway.py @@ -223,9 +223,18 @@ def test_integrations(): uri='http://httpbin.org/robots.txt', ) response.should.equal({ + 'ResponseMetadata': {'HTTPStatusCode': 200}, + 'httpMethod': 'GET', + 'integrationResponses': { + '200': { + 'responseTemplates': { + 'application/json': None + }, + 'statusCode': 200 + } + }, 'type': 'HTTP', - 'uri': 'http://httpbin.org/robots.txt', - 'ResponseMetadata': {'HTTPStatusCode': 200} + 'uri': 'http://httpbin.org/robots.txt' }) response = client.get_integration( @@ -234,9 +243,18 @@ def test_integrations(): httpMethod='GET' ) response.should.equal({ + 'ResponseMetadata': {'HTTPStatusCode': 200}, + 'httpMethod': 'GET', + 'integrationResponses': { + '200': { + 'responseTemplates': { + 'application/json': None + }, + 'statusCode': 200 + } + }, 'type': 'HTTP', - 'uri': 'http://httpbin.org/robots.txt', - 'ResponseMetadata': {'HTTPStatusCode': 200} + 'uri': 'http://httpbin.org/robots.txt' }) response = client.get_resource( @@ -244,6 +262,15 @@ def test_integrations(): resourceId=root_id, ) response['resourceMethods']['GET']['methodIntegration'].should.equal({ + 'httpMethod': 'GET', + 'integrationResponses': { + '200': { + 'responseTemplates': { + 'application/json': None + }, + 'statusCode': 200 + } + }, 'type': 'HTTP', 'uri': 'http://httpbin.org/robots.txt' }) @@ -261,6 +288,101 @@ def test_integrations(): response['resourceMethods']['GET'].shouldnt.contain("methodIntegration") +@mock_apigateway +def test_integration_response(): + client = boto3.client('apigateway', region_name='us-west-2') + response = client.create_rest_api( + name='my_api', + description='this is my api', + ) + api_id = response['id'] + + resources = client.get_resources(restApiId=api_id) + root_id = [resource for resource in resources['items'] if resource['path'] == '/'][0]['id'] + + client.put_method( + restApiId=api_id, + resourceId=root_id, + httpMethod='GET', + authorizationType='none', + ) + + client.put_method_response( + restApiId=api_id, + resourceId=root_id, + httpMethod='GET', + statusCode='200', + ) + + response = client.put_integration( + restApiId=api_id, + resourceId=root_id, + httpMethod='GET', + type='HTTP', + uri='http://httpbin.org/robots.txt', + ) + + response = client.put_integration_response( + restApiId=api_id, + resourceId=root_id, + httpMethod='GET', + statusCode='200', + selectionPattern='foobar', + ) + response.should.equal({ + 'statusCode': '200', + 'selectionPattern': 'foobar', + 'ResponseMetadata': {'HTTPStatusCode': 200}, + 'responseTemplates': { + 'application/json': None + } + }) + + response = client.get_integration_response( + restApiId=api_id, + resourceId=root_id, + httpMethod='GET', + statusCode='200', + ) + response.should.equal({ + 'statusCode': '200', + 'selectionPattern': 'foobar', + 'ResponseMetadata': {'HTTPStatusCode': 200}, + 'responseTemplates': { + 'application/json': None + } + }) + + response = client.get_method( + restApiId=api_id, + resourceId=root_id, + httpMethod='GET', + ) + response['methodIntegration']['integrationResponses'].should.equal({ + '200': { + 'responseTemplates': { + 'application/json': None + }, + 'selectionPattern': 'foobar', + 'statusCode': '200' + } + }) + + response = client.delete_integration_response( + restApiId=api_id, + resourceId=root_id, + httpMethod='GET', + statusCode='200', + ) + + response = client.get_method( + restApiId=api_id, + resourceId=root_id, + httpMethod='GET', + ) + response['methodIntegration']['integrationResponses'].should.equal({}) + + @mock_apigateway def test_deployment(): client = boto3.client('apigateway', region_name='us-west-2')