Closed scarlier closed 2 years ago
I need to explicitly add permissions to API gateway to invoke Lambda function. Adding this resource helped to fix permissions issue.
TestApiGatewayInvokePermissions:
Type: AWS::Lambda::Permission
DependsOn:
- TestLambdaFunction
- TestServiceApi
Properties:
Action: lambda:invokeFunction
FunctionName:
Ref: TestLambdaFunction
SourceArn:
Fn::Sub: arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${TestServiceApi}/*
Principal: apigateway.amazonaws.com
Thanks a lot again @paolorechia
+1
+1
Well that's it. I am giving up on SAM.
I ended up setting up a two-phase deployment with my CD pipeline (GitHub Actions)
sam deploy
aws apigateway create-request-validator
and note the id downaws apigateway update-method
Commit those changes with aws apigateway create-deployment
So far so good
My workaround as a step in CI/CD (after successful Cloudfromation deploy):
#!/usr/bin/env python3
import os
import boto3
from typing import Optional
from argparse import ArgumentParser
from utils.config import VaultConfig
client = boto3.client("apigateway", region_name=os.environ.get("AWS_REGION"))
validator_name = "validate-all"
def get_api_id(api_name: str) -> str:
api_ids = []
for api_conf in client.get_rest_apis(limit=500).get("items"):
if api_conf.get("name") == api_name:
api_ids.append(api_conf.get("id"))
if len(api_ids) != 1:
raise Exception(f"Could not define Api ID by Api Name - {api_ids}")
return api_ids[0]
def get_resources(api_id: str) -> dict:
resources = {}
paginator = client.get_paginator("get_resources")
response_iterator = paginator.paginate(
restApiId=api_id, PaginationConfig={"MaxItems": 100}
)
for page in response_iterator:
for each in page.get("items"):
_id = each["id"]
_methods = each.get("resourceMethods") or []
for _method in _methods:
if _method not in ("OPTIONS", "ANY"):
resources.setdefault(_id, []).append(_method)
return resources
def get_validator_id(api_id: str) -> str:
validators = client.get_request_validators(restApiId=api_id, limit=500).get("items")
if not validators:
print("Creating new RequestValidator...")
return create_validator(api_id)
for _validator in validators:
if _validator.get("name") == validator_name:
print(f"Using RequestValidator {validator_name} that already exists")
return _validator.get("id")
def create_validator(api_id: str) -> str:
r = client.create_request_validator(
restApiId=api_id,
name=validator_name,
validateRequestBody=True,
validateRequestParameters=True,
)
return r.get("id")
def set_validator(api_id: str, resource_id: str, method: str, validator: str) -> None:
client.update_method(
restApiId=api_id,
resourceId=resource_id,
httpMethod=method,
patchOperations=[
{"op": "replace", "path": "/requestValidatorId", "value": validator},
],
)
def deploy_api(api_id: str, env: str, desc: str) -> None:
client.create_deployment(restApiId=api_id, stageName=env, description=desc)
def remove_validator(api_id: str, validator_id: str) -> None:
client.delete_request_validator(restApiId=api_id, requestValidatorId=validator_id)
def skip(api_set_request_validator: bool) -> None:
print(f"########################################\n"
f"RequestValidator processing was skipped:\n"
f"API_SET_REQUEST_VALIDATOR = {api_set_request_validator}\n"
f"########################################")
exit(0)
def run(config: VaultConfig, remove_request_validator: Optional[bool]) -> None:
api = get_api_id(config.api_name)
validator_id = get_validator_id(api)
if remove_request_validator:
remove_validator(api_id=api, validator_id=validator_id)
print(f"RequestValidator {validator_id} was removed")
else:
for res, methods in get_resources(api).items():
for method_name in methods:
set_validator(api, res, method_name, validator_id)
print(
f"Successfully set Validator {validator_id} for Resource {res}/{method_name}"
)
deploy_api(api, config.env, config.ci_pipeline_url)
print(f"Successfully deploy {config.api_name}:{config.env} ({api})")
if __name__ == "__main__":
parser = ArgumentParser()
parser.add_argument("--remove", action="store_true")
args = parser.parse_args()
conf = VaultConfig()
if not conf.api_set_request_validator:
skip(conf.api_set_request_validator)
run(config=conf, remove_request_validator=args.remove)
Well that's it. I am giving up on SAM.
@chrisj-au Don't give-up
I'm able to validate incoming and outgoing request using Use DefinitionBody or DefinitionUri
DefinitionBody:
swagger: 2.0
x-amazon-apigateway-request-validators:
basic:
validateRequestBody: true
validateRequestParameters: true
x-amazon-apigateway-request-validator: basic
paths:
/:
post:
x-amazon-apigateway-integration:
httpMethod: POST
type: aws_proxy
uri:
Fn::Sub: 'arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${ApiTestFunction.Arn}/invocations'
parameters:
- required: true
in: body
name: profileModel
schema:
$ref: '#/definitions/Profile'
+1
@praneetap any updates?
+1
+1
any ETA?
+1
+1
+1 totally not understandable why request validator is not included in SAM
+1
+1
+1
Yes please!
+1
This feature would make so much sense..
+1
+1
+1
+1
+1
+1
+1
+1
+1 (and it's somewhat annoying to have to waste time on this topic)
I have added a PR to try fix this: https://github.com/aws/serverless-application-model/pull/2026 I also need when deploy a model set the validation to the route/method.
If someone could review and give a +1.
+1, we need this!
Ok, so I'm not going mad: I've spent several days trying to get SAM to add a Request Validator. Looks like the PR above will make this simple to do. +1
+1
Now that the solution was implemented. Can somebody explain to me what is the main advantage of having validation as a Request Validator instead of validating in the code?
My guess it that AWS won't even charge me if the request validation failed, while if I do the validation in the code AWS will charge me for the seconds the code spent validating. Is this guess accurate?
@AllanOricil I mean, why do something by yourself when you can outsource it to AWS? :) Also, it's a win-win for overall request latency.
Has this feature been released?
@AllanOricil I mean, why do something by yourself when you can outsource it to AWS? :) Also, it's a win-win for overall request latency.
@AntonUspehov but does AWS charge me for the time the Request Validator validation takes or per validation/request?
@AllanOricil I mean, why do something by yourself when you can outsource it to AWS? :) Also, it's a win-win for overall request latency.
@AntonUspehov, but does AWS charge me for the time the Request Validator validation takes or per validation/request?
@AllanOricil No, only for the API Gateway request, as I know. Lambda won't even be trigger.
@AllanOricil I mean, why do something by yourself when you can outsource it to AWS? :) Also, it's a win-win for overall request latency.
@AntonUspehov, but does AWS charge me for the time the Request Validator validation takes or per validation/request?
@AllanOricil No, only for the API Gateway request, as I know. Lambda won't even be trigger.
Cool. I will start testing it :D Amazing job guys. If anybody here needs a serverless app developer, you can count on me as well.
This feature has been released.
I have a question regarding this feature @moelasmar. Typically, one would want to validate for request parametes only. But in order to do this you need to define a RequestModel, would it be better being able to enable parameterValidation from requestParameters instead?
@santiperone I created another PR for this scenario: https://github.com/aws/serverless-application-model/pull/2450
A thumbs up at the PR would be appreciated!
Team, currently there seems to be a missing piece, when adding request parameters to the SAM template as below, the request parameters get added properly, however the "Request validator" flag doesn't get set and remain None. Our SAM docs for EventSource doesn't seem to have a property to set the Request Validator. Am I missing something?
Events:
ServerlessRestApiGETMethod:
Type: Api
Properties:
RestApiId: !Ref Api
Path: /my-path
Method: GET
RequestParameters:
- method.request.querystring.param1:
Required: true
- method.request.querystring.param2:
Required: true
cc @moelasmar
Cheers
I had created this PR to address it, but it was not accepted, it is something I would like really implemented, but never got clear directive of better implementation of it. I would be happy to cut a new PR to do it if I have clear direction on it. cc: @moelasmar My PR: https://github.com/aws/serverless-application-model/pull/2450
Just switch to cdk or pollumi. Use SAM for testing your lambdas locally. Much easier than write these templates by hand
Is this topic dead?
Description: Defining api model to required=true will not add the Request Validator to the method.
with following sam template and sam cli version 0.40
Observed result: Request Validator in method settings has value "NONE"
Expected result: Request Validator in method settings has value "Validate body..."