aws-sam-cli icon indicating copy to clipboard operation
aws-sam-cli copied to clipboard

Support --queryStringParameters parameter when generating api gateway aws-proxy event

Open lvthillo opened this issue 4 years ago • 2 comments

Describe your idea/feature/enhancement

I want to generate an API GW event to test my lambda locally. My lambda expects queryStringParameters.

I tried: sam local generate-event apigateway aws-proxy --method GET --path document --body "" --queryStringParameters "{"documentId": "1044", "versionId": "v_1"}"

Error: no such option: --queryStringParameters

Proposal

It's not clear how I can generate an event with custom queryStringParameters. I don't want to edit the json manually if possible.

It would be nice to have some thing like the parameter --queryStringParameters to make it easy to generate queryStringParameters inside the event.json

lvthillo avatar Mar 19 '20 14:03 lvthillo

@lvthillo Right now, we don't have a better way than generating the event and then editing the output to add the query parameters. This should be something simple to add, would you be interested in contributing it?

jfuss avatar Mar 19 '20 21:03 jfuss

@jfuss I was checking in the code base and I don't know if it's really simple. This is samcli/lib/generated_sample_events/events/apigateway/AwsProxy.json

{
  "body": "{{{body}}}",
  "resource": "{{{resource}}}",
  "path": "/{{{path}}}",
  "httpMethod": "{{{method}}}",
  "isBase64Encoded": true,
  "queryStringParameters": {
    "foo": "bar"
  },
  ...

As you can see the queryStringParameters value is of type dict and not a string like all the others. So if I understand correctly I can not just update the samcli/lib/generated_sample_events/event-mapping.json and just add:

        "querystringparameters": {
          "type": "string",
          "default": "{"foo": "bar"}"
        },

It should be something like (dict and without quotes):

        "querystringparameters": {
          "type": "dict",
          "default": {"foo": "bar"}
        },

The output:

samdev local generate-event apigateway aws-proxy --method GET --path document --body "hello"
{'method': 'GET', 'path': 'document', 'body': 'aGVsbG8=', 'stage': 'prod', 'querystringparameters': {'test': 'body'}, 'resource': '/{proxy+}', 'account_id': '123456789012', 'dns_suffix': 'us-east-1.amazonaws.com'}

But here it's substituted as a string

{
  "body": "aGVsbG8=",
  "resource": "/{proxy+}",
  "path": "/document",
  "httpMethod": "GET",
  "isBase64Encoded": true,
  "queryStringParameters": "{'test': 'body'}",
  "multiValueQueryStringParameters": {
    "foo": [
      "bar"
    ]
  },

The 'issue' seems to occur here:

        # open the file
        with open(file_path) as f:
            data = json.load(f)

        data = json.dumps(data, indent=2)
        
        # return the substituted file
        return renderer.render(data, values_to_sub)

We're passing in the data as JSON but "{"key":"value"}" is a string and not a dict. A (probably not so good) idea could be to check if there are dicts in the values_to_sub and for each dict replace the json loaded "{"key":"value"}" with {"key":"value"}

Example:

import chevron
import json

def convert_dicts(data):
    updated_data = data
    for key, value in values_to_sub.items():
        if type(value) is dict:
            substitution = "{{{%s}}}" % key
            updated_data = updated_data.replace('"%s"' % substitution, substitution)
    return updated_data

if __name__== "__main__":
    values_to_sub = {'method': 'GET', 'path': 'document', 'body': 'aGVsbG8=', 'stage': 'prod', 'querystringparameters': {'test': 'body'}, 'resource': '/{proxy+}', 'test': {'test': 'jo'}}

    data = '''
    {
    "body": "{{{body}}}",
    "resource": "{{{resource}}}",
    "path": "/{{{path}}}",
    "httpMethod": "{{{method}}}",
    "isBase64Encoded": true,
    "queryStringParameters": "{{{querystringparameters}}}",
    "multiValueQueryStringParameters": {
        "foo": [
        "bar"
        ]
    },
    "test": "{{{test}}}"
    }
    '''

    output = convert_dicts(data)
    test = chevron.render(output, values_to_sub)
    print(test)

output:

    {
    "body": "aGVsbG8=",
    "resource": "/{proxy+}",
    "path": "/document",
    "httpMethod": "GET",
    "isBase64Encoded": true,
    "queryStringParameters": {'test': 'body'},
    "multiValueQueryStringParameters": {
        "foo": [
        "bar"
        ]
    },
    "test": {'test': 'jo'}
    }

lvthillo avatar Mar 21 '20 19:03 lvthillo