Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add RequestParameters Support #953

Merged
merged 42 commits into from
Aug 14, 2019
Merged
Show file tree
Hide file tree
Changes from 36 commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
de44b33
chore: Delete nodejs-upgrade-functions sample app
Apr 10, 2019
8798806
docs: update example apps from nodejs6.10 to nodejs8.10 (#883)
carvantes Apr 10, 2019
1fd6dc3
chore: Delete misplaced package.json in several example apps
Apr 11, 2019
4e8723a
chore: run cfn lint on translator test output (#888)
keetonian Apr 13, 2019
7209ed4
feat: custom CodeDeploy configurations in DeploymentPreference (#848)
Buffer0x7cd Apr 16, 2019
2b2ea35
docs: update lambda_safe_deployments example to use nodejs8.10 for th…
sullis May 2, 2019
973a187
docs: add Auth to supported Api Global properties (#899)
keetonian May 3, 2019
f762241
docs: fix typo in DEVELOPMENT_GUIDE (#902)
lestephane May 3, 2019
61c094b
docs: update globals.rst (#905)
keetonian May 3, 2019
97bacc3
feat(policy-templates): add new policy for allowing step functions ex…
ljacobsson May 3, 2019
1571c33
docs: add S3 filter example to docs (#909)
charliejllewellyn May 7, 2019
fee6bb6
chore: bump version to 1.12.0 (#910)
keetonian May 7, 2019
d18c2fa
fix: fix Internal transform failure on bad Condition syntax (#908)
jadhavmanoj May 8, 2019
82f4ef7
fix: internal transform failure on path parameters (#913)
jadhavmanoj May 17, 2019
f532185
docs: update generated_resources.rst (#919)
ingve May 17, 2019
6352f8a
fix: invalid event type error (#918)
praneetap May 17, 2019
1255690
chore: update requirements.txt (#928)
keetonian May 20, 2019
41fb86a
chore: update base.txt (#927)
keetonian May 20, 2019
c85796f
test: added test cases for semantic version check (#929)
jadhavmanoj May 21, 2019
73cf9d3
chore: update test_translator.py (#933)
keetonian May 24, 2019
a27fa65
fix: partitionalize arn in StepFunctionsExecutionPolicy (#941)
keetonian May 29, 2019
fe01a9c
added RequestParameters property to Api event source
beck3905 Jun 5, 2019
7dacb5f
switch namedtuple to dictionary with default values
beck3905 Jun 5, 2019
5ca3afd
removed unnecessary import
beck3905 Jun 5, 2019
1941f5a
added swagger tests
beck3905 Jun 5, 2019
41d4b2e
added end to end tests for request parameters
beck3905 Jun 5, 2019
17a6bcd
merge latest from upstream/develop
beck3905 Jun 5, 2019
9e21f6b
fix get first request parameter after test failure
beck3905 Jun 7, 2019
4078aa4
changed dictionary to list to preserve order of parameters
beck3905 Jun 7, 2019
628b387
merge from upstream/develop
beck3905 Jun 11, 2019
bf37e0f
merge from upstream/develop
beck3905 Jun 19, 2019
a6736e9
added request parameters example
beck3905 Jun 19, 2019
1e5a862
fixed CodeUri
beck3905 Jun 19, 2019
9e33bb1
updated documentation for request parameters
beck3905 Jun 19, 2019
6d5a95b
merge from upstream/develop
beck3905 Jul 3, 2019
1638c0c
merged from upstream/develop
beck3905 Jul 11, 2019
2e87325
merge from upstream/develop
beck3905 Jul 29, 2019
c1b7b35
updated error messages for request parameters
beck3905 Jul 29, 2019
3869046
Merge remote-tracking branch 'remotes/upstream/develop' into api-even…
beck3905 Aug 6, 2019
99aedd9
change query to querystring; fix styling
beck3905 Aug 7, 2019
7ec7d1a
minor cleanups
jlhood Aug 13, 2019
5b8f75b
Merge branch 'develop' into api-event-parameters
jlhood Aug 13, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
exports.handler = function(event, context, callback) {
callback(null, {
"statusCode": 200,
"body": "hello world"
});
}
28 changes: 28 additions & 0 deletions examples/2016-10-31/function_request_parameters/template.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: Simple API Endpoint configured using Swagger specified inline and backed by a Lambda function
Resources:

MyLambdaFunction:
Type: AWS::Serverless::Function
Properties:
Handler: index.handler
Runtime: nodejs8.10
CodeUri: src/
Events:
GetApi:
Type: Api
Properties:
Path: /post
Method: POST
RequestParameters:
- method.request.header.Authorization:
Required: True
Caching: True
beck3905 marked this conversation as resolved.
Show resolved Hide resolved
- method.request.query.type
beck3905 marked this conversation as resolved.
Show resolved Hide resolved

Outputs:

ApiURL:
Description: "API endpoint URL for Prod environment"
Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/prod/get"
jlhood marked this conversation as resolved.
Show resolved Hide resolved
55 changes: 54 additions & 1 deletion samtranslator/model/eventsources/push.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@

CONDITION = 'Condition'

RequestParameterProperties = ["Required", "Caching"]
jlhood marked this conversation as resolved.
Show resolved Hide resolved


class PushEventSource(ResourceMacro):
"""Base class for push event sources for SAM Functions.
Expand Down Expand Up @@ -390,7 +392,8 @@ class Api(PushEventSource):
# Api Event sources must "always" be paired with a Serverless::Api
'RestApiId': PropertyType(True, is_str()),
'Auth': PropertyType(False, is_type(dict)),
'RequestModel': PropertyType(False, is_type(dict))
'RequestModel': PropertyType(False, is_type(dict)),
'RequestParameters': PropertyType(False, is_type(list))
}

def resources_to_link(self, resources):
Expand Down Expand Up @@ -600,6 +603,56 @@ def _add_swagger_integration(self, api, function):
editor.add_request_model_to_method(path=self.Path, method_name=self.Method,
request_model=self.RequestModel)

if self.RequestParameters:

default_value = {
'Required': False,
'Caching': False
}

parameters = []
for parameter in self.RequestParameters:

if isinstance(parameter, dict):

parameter_name, parameter_value = next(iter(parameter.items()))

if not re.match('method\.request\.(query|path|header)', parameter_name):
beck3905 marked this conversation as resolved.
Show resolved Hide resolved
raise InvalidEventException(
self.relative_id,
"Invalid value for 'RequestParameters' property")
praneetap marked this conversation as resolved.
Show resolved Hide resolved

if not isinstance(parameter_value, dict) or not all(key in RequestParameterProperties
for key in parameter_value.keys()):
raise InvalidEventException(
self.relative_id,
"Invalid value for 'RequestParameters' property")
praneetap marked this conversation as resolved.
Show resolved Hide resolved

settings = default_value.copy()
settings.update(parameter_value)
settings.update({'Name': parameter_name})

parameters.append(settings)

elif not isinstance(parameter, string_types):
raise InvalidEventException(
self.relative_id,
"Invalid value for 'RequestParameters' property")
praneetap marked this conversation as resolved.
Show resolved Hide resolved

else:
praneetap marked this conversation as resolved.
Show resolved Hide resolved
if not re.match('method\.request\.(query|path|header)', parameter):
raise InvalidEventException(
self.relative_id,
"Invalid value for 'RequestParameters' property")
praneetap marked this conversation as resolved.
Show resolved Hide resolved

settings = default_value.copy()
settings.update({'Name': parameter})

parameters.append(settings)

editor.add_request_parameters_to_method(path=self.Path, method_name=self.Method,
request_parameters=parameters)

api["DefinitionBody"] = editor.swagger


Expand Down
44 changes: 44 additions & 0 deletions samtranslator/swagger/swagger.py
Original file line number Diff line number Diff line change
Expand Up @@ -778,6 +778,50 @@ def add_models(self, models):

self.definitions[model_name.lower()] = schema

def add_request_parameters_to_method(self, path, method_name, request_parameters):
"""
Add Parameters to Swagger.

:param string path: Path name
:param string method_name: Method name
:param list request_parameters: Dictionary of Parameters
:return:
"""

normalized_method_name = self._normalize_method_name(method_name)
# It is possible that the method could have two definitions in a Fn::If block.
for method_definition in self.get_method_contents(self.get_path(path)[normalized_method_name]):

# If no integration given, then we don't need to process this definition (could be AWS::NoValue)
if not self.method_definition_has_integration(method_definition):
continue

existing_parameters = method_definition.get('parameters', [])

for request_parameter in request_parameters:

parameter_name = request_parameter['Name']
location_name = parameter_name.replace('method.request.', '')
location, name = location_name.split('.')

parameter = {
'in': location,
beck3905 marked this conversation as resolved.
Show resolved Hide resolved
'name': name,
'required': request_parameter['Required'],
'type': 'string'
}

existing_parameters.append(parameter)

if request_parameter['Caching']:

integration = method_definition[self._X_APIGW_INTEGRATION]
cache_parameters = integration.get('cacheKeyParameters', [])
beck3905 marked this conversation as resolved.
Show resolved Hide resolved
cache_parameters.append(parameter_name)
integration['cacheKeyParameters'] = cache_parameters

method_definition['parameters'] = existing_parameters

@property
def swagger(self):
"""
Expand Down
135 changes: 135 additions & 0 deletions tests/swagger/test_swagger.py
Original file line number Diff line number Diff line change
Expand Up @@ -1116,6 +1116,7 @@ def test_must_add_body_parameter_to_method_openapi_required_true(self):

self.assertEqual(expected, editor.swagger['paths']['/foo']['get']['requestBody'])


class TestSwaggerEditor_add_auth(TestCase):

def setUp(self):
Expand Down Expand Up @@ -1231,3 +1232,137 @@ def test_set_method_apikey_handling_apikeyrequired_true(self):

self.editor._set_method_apikey_handling(path, method, True)
self.assertEqual(expected, self.editor.swagger["paths"][path][method]["security"])


class TestSwaggerEditor_add_request_parameter_to_method(TestCase):

def setUp(self):
self.original_swagger = {
"swagger": "2.0",
"paths": {
"/foo": {
'get': {
'x-amazon-apigateway-integration': {
'test': 'must have integration'
}
}
}
}
}

self.editor = SwaggerEditor(self.original_swagger)

def test_must_add_parameter_to_method_with_required_and_caching_true(self):

parameters = [{
'Name': 'method.request.header.Authorization',
'Required': True,
'Caching': True
}]

self.editor.add_request_parameters_to_method('/foo', 'get', parameters)

expected_parameters = [
{
'in': 'header',
'required': True,
'name': 'Authorization',
'type': 'string'
}
]

method_swagger = self.editor.swagger['paths']['/foo']['get']

self.assertEqual(expected_parameters, method_swagger['parameters'])
self.assertEqual(['method.request.header.Authorization'], method_swagger[_X_INTEGRATION]['cacheKeyParameters'])

def test_must_add_parameter_to_method_with_required_and_caching_false(self):

parameters = [{
'Name': 'method.request.header.Authorization',
'Required': False,
'Caching': False
}]

self.editor.add_request_parameters_to_method('/foo', 'get', parameters)

expected_parameters = [
{
'in': 'header',
'required': False,
'name': 'Authorization',
'type': 'string'
}
]

method_swagger = self.editor.swagger['paths']['/foo']['get']

self.assertEqual(expected_parameters, method_swagger['parameters'])
self.assertNotIn('cacheKeyParameters', method_swagger[_X_INTEGRATION].keys())

def test_must_add_parameter_to_method_with_existing_parameters(self):

original_swagger = {
"swagger": "2.0",
"paths": {
"/foo": {
'get': {
'x-amazon-apigateway-integration': {
'test': 'must have integration'
},
'parameters': [{'test': 'existing parameter'}]
}
}
}
}

editor = SwaggerEditor(original_swagger)

parameters = [{
'Name': 'method.request.header.Authorization',
'Required': False,
'Caching': False
}]

editor.add_request_parameters_to_method('/foo', 'get', parameters)

expected_parameters = [
{
'test': 'existing parameter'
},
{
'in': 'header',
'required': False,
'name': 'Authorization',
'type': 'string'
}
]

method_swagger = editor.swagger['paths']['/foo']['get']

self.assertEqual(expected_parameters, method_swagger['parameters'])
self.assertNotIn('cacheKeyParameters', method_swagger[_X_INTEGRATION].keys())

def test_must_not_add_parameter_to_method_without_integration(self):
original_swagger = {
"swagger": "2.0",
"paths": {
"/foo": {
'get': {}
}
}
}

editor = SwaggerEditor(original_swagger)

parameters = [{
'Name': 'method.request.header.Authorization',
'Required': True,
'Caching': True
}]

editor.add_request_parameters_to_method('/foo', 'get', parameters)

expected = {}

self.assertEqual(expected, editor.swagger['paths']['/foo']['get'])
Loading