Skip to content

Commit

Permalink
Merge a365b18 into 8a55432
Browse files Browse the repository at this point in the history
  • Loading branch information
mhmoudgmal committed Oct 17, 2018
2 parents 8a55432 + a365b18 commit 8fe1043
Show file tree
Hide file tree
Showing 5 changed files with 35 additions and 3 deletions.
22 changes: 21 additions & 1 deletion localstack/services/apigateway/apigateway_listener.py
Expand Up @@ -3,6 +3,7 @@
import json
import requests
import dateutil.parser
from six.moves.urllib import parse as urlparse
from requests.models import Response
from flask import Response as FlaskResponse
from localstack.constants import APPLICATION_JSON, PATH_USER_REQUEST
Expand Down Expand Up @@ -121,6 +122,21 @@ def extract_path_params(path, extracted_path):
return path_params


def extract_query_string_params(path):
parsed_path = urlparse.urlparse(path)
path = parsed_path.path
parsed_query_string_params = urlparse.parse_qs(parsed_path.query)

query_string_params = {}
for query_param_name, query_param_values in parsed_query_string_params.items():
if len(query_param_values) == 1:
query_string_params[query_param_name] = query_param_values[0]
else:
query_string_params[query_param_name] = query_param_values

return [path, query_string_params]


def get_resource_for_path(path, path_map):
matches = []
for api_path, details in path_map.items():
Expand Down Expand Up @@ -214,12 +230,16 @@ def forward_request(self, method, path, data, headers):
func_arn = uri.split(':lambda:path')[1].split('functions/')[1].split('/invocations')[0]
data_str = json.dumps(data) if isinstance(data, dict) else data

relative_path, query_string_params = extract_query_string_params(path=relative_path)

try:
path_params = extract_path_params(path=relative_path, extracted_path=extracted_path)
except Exception:
path_params = {}

result = lambda_api.process_apigateway_invocation(func_arn, relative_path, data_str,
headers, path_params=path_params, method=method, resource_path=path)
headers, path_params=path_params, query_string_params=query_string_params,
method=method, resource_path=path)

if isinstance(result, FlaskResponse):
return flask_to_requests_response(result)
Expand Down
4 changes: 2 additions & 2 deletions localstack/services/awslambda/lambda_api.py
Expand Up @@ -156,7 +156,7 @@ def use_docker():


def process_apigateway_invocation(func_arn, path, payload, headers={},
resource_path=None, method=None, path_params={}):
resource_path=None, method=None, path_params={}, query_string_params={}):
try:
resource_path = resource_path or path
event = {
Expand All @@ -167,7 +167,7 @@ def process_apigateway_invocation(func_arn, path, payload, headers={},
'isBase64Encoded': False,
'resource': resource_path,
'httpMethod': method,
'queryStringParameters': {}, # TODO
'queryStringParameters': query_string_params,
'stageVariables': {} # TODO
}
return run_lambda(event=event, context={}, func_arn=func_arn)
Expand Down
1 change: 1 addition & 0 deletions tests/integration/lambdas/lambda_integration.py
Expand Up @@ -31,6 +31,7 @@ def handler(event, context):
except Exception:
body = {}
body['pathParameters'] = event.get('pathParameters')
body['queryStringParameters'] = event.get('queryStringParameters')
body['httpMethod'] = event.get('httpMethod')
return {
'body': body,
Expand Down
4 changes: 4 additions & 0 deletions tests/integration/test_api_gateway.py
Expand Up @@ -34,6 +34,7 @@
API_PATH_DATA_INBOUND = '/data'
API_PATH_HTTP_BACKEND = '/hello_world'
API_PATH_LAMBDA_PROXY_BACKEND = '/lambda/{test_param1}'

API_PATH_LAMBDA_PROXY_BACKEND_ANY_METHOD = '/lambda-any-method/{test_param1}'
# name of Kinesis stream connected to API Gateway
TEST_STREAM_KINESIS_API_GW = 'test-stream-api-gw'
Expand Down Expand Up @@ -180,6 +181,8 @@ def test_api_gateway_lambda_proxy_integration():

# make test request to gateway and check response
path = API_PATH_LAMBDA_PROXY_BACKEND.replace('{test_param1}', 'foo1')
path = path + '?foo=foo&bar=bar&bar=baz'

url = INBOUND_GATEWAY_URL_PATTERN.format(api_id=result['id'], stage_name=TEST_STAGE_NAME, path=path)
data = {'return_status_code': 203, 'return_headers': {'foo': 'bar123'}}
result = requests.post(url, data=json.dumps(data))
Expand All @@ -189,6 +192,7 @@ def test_api_gateway_lambda_proxy_integration():
assert parsed_body.get('return_status_code') == 203
assert parsed_body.get('return_headers') == {'foo': 'bar123'}
assert parsed_body.get('pathParameters') == {'test_param1': 'foo1'}
assert parsed_body.get('queryStringParameters') == {'foo': 'foo', 'bar': ['bar', 'baz']}
result = requests.delete(url, data=json.dumps(data))
assert result.status_code == 404

Expand Down
7 changes: 7 additions & 0 deletions tests/unit/test_apigateway.py
Expand Up @@ -4,6 +4,13 @@

class ApiGatewayPathsTest (unittest.TestCase):

def test_extract_query_params(self):
path, query_params = apigateway_listener.extract_query_string_params(
'/foo/bar?foo=foo&bar=bar&bar=baz'
)
self.assertEqual(path, '/foo/bar')
self.assertEqual(query_params, {'foo': 'foo', 'bar': ['bar', 'baz']})

def test_extract_path_params(self):
params = apigateway_listener.extract_path_params('/foo/bar', '/foo/{param1}')
self.assertEqual(params, {'param1': 'bar'})
Expand Down

0 comments on commit 8fe1043

Please sign in to comment.