Validating query string parameters and request body in AWS lambda using webargs

3.5k views Asked by At

I am trying to figure out ways of validating query string parameters for an API created using AWS API gateway and backed by a Python Lambda function. API Gateway can validate the presence of the required query string parameters. However, I could not find a way for additional validations such as determining if the length of a certain parameter is within some limit (e.g. config_id should be minimum 7 characters long). Such validations are possible for the request body using the API Gateway request validation. Refer this link. However, for the query string paramaters only required/not required validation is possible as it does not use any json schema for validation.

Hence, to overcome this issue, I decided to try the webargs module in Python for validating the query string parameters. It is generally used for request validations for APIs created using Python frameworks such as flask or django. I am using the core parser (Refer webargs doc) as follows:

from webargs import fields, validate, core, ValidationError
parser = core.Parser()

params = {"config_id": fields.Str(required=True, validate=lambda p: len(p) >= 7)}

def main(event, context: Dict):
    try:
        # print(event["queryStringParameters"])
        input_params = event.get("queryStringParameters")
        print("queryStringParameters: ", str(input_params))

        if input_params is None:
            input_params = {}
        parsed_params = parser.parse(params, input_params)
        print("parsedParams: ", str(parsed_params))
    except ValidationError as e:
        return {
            "statusCode": 400,
            "headers": {
                "Access-Control-Allow-Origin": "*",
                "Access-Control-Allow-Credentials": True,
                "x-amzn-ErrorType": "ValidationError",
            },
            "body": str(e),
        }

This is how the validation is done in the lambda function. However, only the required validation works correctly. When I pass a config_id of length 5 it does not return any error and proceeds further in the lambda function.

What could be going wrong with this? The parser seems to work, however, the validate function doesn't. Any help is appreciated as I am new to this. Also, is there a better way of doing validations in lambda functions especially for queryStringParameters? It can be handled by the code, but we can have many parameters and many APIs which makes writing code for all such validations a cumbersome task. The webargs module comes in handy.

1

There are 1 answers

1
Sarthak Jain On BEST ANSWER

webargs Library is mostly used for validating HTTP Requests coming via popular Python frameworks like Flask, Django, Bottle etc. The core Parser that you are trying to use should not be used directly as it does not have the methods like load_json, load_query etc implemented (Source code showing the missing implementation here). There are child class implementations of the core parser for each of the frameworks, but using them on API GW does not make sense.

So it's better to use a simpler json validation library like jsonschema. I've modified your code to use jsonschema instead of webargs as follows -

from jsonschema import validate, ValidationError

schema = {
     "type" : "object",
     "properties" : {
         "queryStringParameters" : {
                "type" : "object",
                "properties": {
                        "config_id": {
                                "type": "string",
                                "minLength": 7,
                        }
                }
        },

     },
 }


def main(event, context):
    try:
        validate(instance=event, schema=schema)
    except ValidationError as e:
        return {
            "statusCode": 400,
            "headers": {
                "Access-Control-Allow-Origin": "*",
                "Access-Control-Allow-Credentials": True,
                "x-amzn-ErrorType": "ValidationError",
            },
            "body": e.message,
        }