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 api_gateway_response config #1270

Open
wants to merge 11 commits into
base: master
Choose a base branch
from
1 change: 1 addition & 0 deletions chalice/cli/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -388,6 +388,7 @@ def generate_models(ctx, stage):
swagger_generator = TemplatedSwaggerGenerator()
model = swagger_generator.generate_swagger(
config.chalice_app,
api_gateway_responses=config.api_gateway_responses
)
ui = UI()
ui.write(json.dumps(model, indent=4, cls=PlanEncoder))
Expand Down
6 changes: 6 additions & 0 deletions chalice/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,12 @@ def api_gateway_policy_file(self):
return self._chain_lookup('api_gateway_policy_file',
varies_per_chalice_stage=True)

@property
def api_gateway_responses(self):
# type: () -> Dict[str, Dict[str, Dict[str, Any]]]
return self._chain_lookup('api_gateway_responses',
varies_per_chalice_stage=True)

@property
def minimum_compression_size(self):
# type: () -> int
Expand Down
3 changes: 2 additions & 1 deletion chalice/deploy/deployer.py
Original file line number Diff line number Diff line change
Expand Up @@ -887,7 +887,8 @@ def __init__(self, swagger_generator):
def handle_restapi(self, config, resource):
# type: (Config, models.RestAPI) -> None
swagger_doc = self._swagger_generator.generate_swagger(
config.chalice_app, resource)
config.chalice_app, resource,
api_gateway_responses=config.api_gateway_responses)
resource.swagger_doc = swagger_doc


Expand Down
15 changes: 13 additions & 2 deletions chalice/deploy/swagger.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,18 @@ def __init__(self, region, deployed_resources):
self._region = region
self._deployed_resources = deployed_resources

def generate_swagger(self, app, rest_api=None):
# type: (Chalice, Optional[RestAPI]) -> Dict[str, Any]
def generate_swagger(self,
app, # type: Chalice
rest_api=None, # type: Optional[RestAPI]
api_gateway_responses=None # type: Dict[str, Any]
):
# type: (...) -> Dict[str, Any]
api = copy.deepcopy(self._BASE_TEMPLATE)
api['info']['title'] = app.app_name
self._add_binary_types(api, app)
self._add_route_paths(api, app)
self._add_resource_policy(api, rest_api)
self._add_api_gateway_responses(api, api_gateway_responses)
return api

def _add_resource_policy(self, api, rest_api):
Expand Down Expand Up @@ -239,6 +244,12 @@ def _add_preflight_request(self, cors, methods, swagger_for_path):
}
swagger_for_path['options'] = options_request

def _add_api_gateway_responses(self, api, api_gateway_responses):
# type: (Dict[str, Any], Optional[Dict[str, Any]]) -> None
if api_gateway_responses:
api.setdefault('x-amazon-apigateway-gateway-responses',
api_gateway_responses)


class CFNSwaggerGenerator(SwaggerGenerator):
def __init__(self):
Expand Down
48 changes: 48 additions & 0 deletions docs/source/topics/configfile.rst
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,17 @@ a default resource policy on the API if an explicit policy is not specified.
This value can be a list or a string of endpoint ids.


``api_gateway_responses``
~~~~~~~~~~~~~~~~~~~~~~~~~

A mapping of key/value pairs. They define how the built-in API Gateway
responses should be configured. The top level keys should map to a gateway
response type, e.g. DEFAULT_4XX, and its value should be a mapping defining
status code, parameters, and/or templates. For more information see examples
below or check out the `AWS API Gateway docs
<https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-swagger-extensions-gateway-responses.html>`_


``api_gateway_policy_file``
~~~~~~~~~~~~~~~~~~~~~~~~~~~

Expand Down Expand Up @@ -431,6 +442,43 @@ The ``prod`` stage will have these environment variables set::
}



API Gateway Responses
~~~~~~~~~~~~~~~~~~~~~

An example of configuring API Gateway responses would look like this::

{
"version": "2.0",
"app_name": "app",
"stages": {
"dev": {
"api_gateway_stage": "dev"
}
},
"api_gateway_responses": {
"DEFAULT_4XX": {
"responseParameters": {
"gatewayresponse.header.Access-Control-Allow-Origin": "'*'"
}
},
"DEFAULT_5XX": {
"responseParameters": {
"gatewayresponse.header.Access-Control-Allow-Origin": "'*'"
}
}
}
}

In this config file, we set up the Default 4XX and Default 5XX API Gateway
responses to set the Access-Control-Allow-Origin header on responses. This can
help out with CORS setup so that any error responses are still allowed across
different origins. For more examples of what you can set, check out the
`AWS API Gateway docs
<https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-swagger-extensions-gateway-responses.html>`_



Per Lambda Examples
~~~~~~~~~~~~~~~~~~~

Expand Down
23 changes: 21 additions & 2 deletions tests/unit/deploy/test_deployer.py
Original file line number Diff line number Diff line change
Expand Up @@ -1309,11 +1309,30 @@ def test_can_generate_swagger_builder(self):
lambda_function=None,
)
app = Chalice(app_name='foo')
config = Config.create(chalice_app=app)
api_gateway_responses = {
"DEFAULT_4XX": {
"responseParameters": {
"gatewayresponse.header.Access-Control-Allow-Origin":
"'domain.com'"
},
"responseTemplates": {
"application/json": "{\"message\": test 4xx b }"
}
},
"INVALID_API_KEY": {
"statusCode": "429",
"responseTemplates": {
"application/json": "{\"message\": test forbidden }"
}
}
}
config = Config.create(chalice_app=app,
api_gateway_responses=api_gateway_responses)
p = SwaggerBuilder(generator)
p.handle(config, rest_api)
assert rest_api.swagger_doc == {'swagger': '2.0'}
generator.generate_swagger.assert_called_with(app, rest_api)
generator.generate_swagger.assert_called_with(
app, rest_api, api_gateway_responses=api_gateway_responses)


class TestDeploymentPackager(object):
Expand Down
27 changes: 27 additions & 0 deletions tests/unit/deploy/test_swagger.py
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,33 @@ def test_apigateway_integration_generation(sample_app, swagger_gen):
assert responses['default'] == {'statusCode': '200'}


def test_can_inject_api_gateway_responses(sample_app, swagger_gen):
api_gateway_responses = {
"DEFAULT_4XX": {
"responseParameters": {
"gatewayresponse.header.Access-Control-Allow-Origin":
"'domain.com'"
},
"responseTemplates": {
"application/json": "{\"message\": test 4xx b }"
}
},
"INVALID_API_KEY": {
"statusCode": "429",
"responseTemplates": {
"application/json": "{\"message\": test forbidden }"
}
}
}
doc = swagger_gen.generate_swagger(
sample_app, api_gateway_responses=api_gateway_responses)

assert 'x-amazon-apigateway-gateway-responses' in doc

assert doc['x-amazon-apigateway-gateway-responses'] == \
api_gateway_responses


def test_can_add_url_captures_to_params(sample_app, swagger_gen):
@sample_app.route('/path/{capture}')
def foo(name):
Expand Down