Skip to content
  • Sponsor localstack/localstack

  • Notifications You must be signed in to change notification settings
  • Fork 4.2k

feature request: Support of $context.requestOverride.status|querystring in apigateway #12621

Closed
@pieronatan

Description

@pieronatan

Is there an existing issue for this?

  • I have searched the existing issues

Feature description

LocalStack does not currently support overriding:

  • responseOverride.status to set HTTP response status
  • requestOverride.querystring to inject query parameters into the integration request

Both work correctly in AWS API Gateway when using Velocity templates (VTL), but fail in LocalStack.


Examples

Override response status code (VTL):

#set($statusCode = $context.authorizer.statusCode)
#if($statusCode == 200)
    ##     Mapping the parameters from the request to the backend
    #foreach($param in $input.params().querystring.keySet())
        #set($context.requestOverride.querystring[$param]= $input.params().querystring.get($param))
        #if($foreach.hasNext) #end
    #end
    {
        "statusCode": 200,
        "message": "Valid scope found"
    }
#else
    #set($context.responseOverride.status = $statusCode)
    {
        "error": $context.authorizer.error
        "statusCode": $statusCode,
    }
#end

In AWS → returns HTTP 200.
In LocalStack → returns HTTP 200, or fails with:

2025-05-15T04:12:58.145  WARN --- [et.reactor-5] l.s.a.n.e.h.gateway_except : Non Gateway Exception raised: line 5, column 13: expected assignment in set directive, got: ($context.requestOverride.querystrin ... ...
 Traceback (most recent call last):
   File "/opt/code/localstack/.venv/lib/python3.11/site-packages/airspeed/operators.py", line 350, in require_next_element
     element = element_spec(self.filename, self._full_text, self.end)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   File "/opt/code/localstack/.venv/lib/python3.11/site-packages/airspeed/operators.py", line 289, in __init__
     self.parse()
   File "/opt/code/localstack/.venv/lib/python3.11/site-packages/airspeed/operators.py", line 1077, in parse
     (var_name,) = self.identity_match(self.START)
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   File "/opt/code/localstack/.venv/lib/python3.11/site-packages/airspeed/operators.py", line 306, in identity_match
     raise NoMatch()
 airspeed.operators.NoMatch
 
 During handling of the above exception, another exception occurred:
 
 Traceback (most recent call last):
   File "/opt/code/localstack/.venv/lib/python3.11/site-packages/rolo/gateway/chain.py", line 166, in handle
     handler(self, self.context, response)
   File "/opt/code/localstack/localstack-core/localstack/services/apigateway/next_gen/execute_api/handlers/integration_request.py", line 119, in __call__
     body, request_override = self.render_request_template_mapping(
                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   File "/opt/code/localstack/localstack-core/localstack/services/apigateway/next_gen/execute_api/handlers/integration_request.py", line 186, in render_request_template_mapping
     body, request_override = self._vtl_template.render_request(
                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   File "/opt/code/localstack/localstack-core/localstack/services/apigateway/next_gen/execute_api/template_mapping.py", line 193, in render_request
     result = self.render_vtl(template=template.strip(), variables=variables_copy)
              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   File "/opt/code/localstack/localstack-core/localstack/utils/aws/templating.py", line 119, in render_vtl
     rendered_template = t.merge(namespace)
                         ^^^^^^^^^^^^^^^^^^
   File "/opt/code/localstack/.venv/lib/python3.11/site-packages/airspeed/operators.py", line 92, in merge
     self.merge_to(namespace, output, loader)
   File "/opt/code/localstack/.venv/lib/python3.11/site-packages/airspeed/operators.py", line 102, in merge_to
     self.ensure_compiled()
   File "/opt/code/localstack/.venv/lib/python3.11/site-packages/airspeed/operators.py", line 97, in ensure_compiled
     self.root_element = TemplateBody(self.filename, self.content)
                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   File "/opt/code/localstack/.venv/lib/python3.11/site-packages/airspeed/operators.py", line 289, in __init__
     self.parse()
   File "/opt/code/localstack/.venv/lib/python3.11/site-packages/airspeed/operators.py", line 1351, in parse
     self.block = self.next_element(Block)
                  ^^^^^^^^^^^^^^^^^^^^^^^^
   File "/opt/code/localstack/.venv/lib/python3.11/site-packages/airspeed/operators.py", line 333, in next_element
     element = element_spec(self.filename, self._full_text, self.end)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   File "/opt/code/localstack/.venv/lib/python3.11/site-packages/airspeed/operators.py", line 289, in __init__
     self.parse()
   File "/opt/code/localstack/.venv/lib/python3.11/site-packages/airspeed/operators.py", line 1368, in parse
     self.next_element(
   File "/opt/code/localstack/.venv/lib/python3.11/site-packages/airspeed/operators.py", line 339, in next_element
     element = element_class(self.filename, self._full_text, self.end)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   File "/opt/code/localstack/.venv/lib/python3.11/site-packages/airspeed/operators.py", line 289, in __init__
     self.parse()
   File "/opt/code/localstack/.venv/lib/python3.11/site-packages/airspeed/operators.py", line 1043, in parse
     self.block = self.require_next_element(Block, "block")
                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   File "/opt/code/localstack/.venv/lib/python3.11/site-packages/airspeed/operators.py", line 350, in require_next_element
     element = element_spec(self.filename, self._full_text, self.end)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   File "/opt/code/localstack/.venv/lib/python3.11/site-packages/airspeed/operators.py", line 289, in __init__
     self.parse()
   File "/opt/code/localstack/.venv/lib/python3.11/site-packages/airspeed/operators.py", line 1368, in parse
     self.next_element(
   File "/opt/code/localstack/.venv/lib/python3.11/site-packages/airspeed/operators.py", line 339, in next_element
     element = element_class(self.filename, self._full_text, self.end)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   File "/opt/code/localstack/.venv/lib/python3.11/site-packages/airspeed/operators.py", line 289, in __init__
     self.parse()
   File "/opt/code/localstack/.venv/lib/python3.11/site-packages/airspeed/operators.py", line 1312, in parse
     self.block = self.next_element(Block)
                  ^^^^^^^^^^^^^^^^^^^^^^^^
   File "/opt/code/localstack/.venv/lib/python3.11/site-packages/airspeed/operators.py", line 333, in next_element
     element = element_spec(self.filename, self._full_text, self.end)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   File "/opt/code/localstack/.venv/lib/python3.11/site-packages/airspeed/operators.py", line 289, in __init__
     self.parse()
   File "/opt/code/localstack/.venv/lib/python3.11/site-packages/airspeed/operators.py", line 1368, in parse
     self.next_element(
   File "/opt/code/localstack/.venv/lib/python3.11/site-packages/airspeed/operators.py", line 339, in next_element
     element = element_class(self.filename, self._full_text, self.end)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   File "/opt/code/localstack/.venv/lib/python3.11/site-packages/airspeed/operators.py", line 289, in __init__
     self.parse()
   File "/opt/code/localstack/.venv/lib/python3.11/site-packages/airspeed/operators.py", line 1291, in parse
     self.assignment = self.require_next_element(Assignment, "assignment")
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   File "/opt/code/localstack/.venv/lib/python3.11/site-packages/airspeed/operators.py", line 352, in require_next_element
     raise self.syntax_error(expected)
 airspeed.operators.TemplateSyntaxError: line 5, column 13: expected assignment in set directive, got: ($context.requestOverride.querystrin ... ...

Environment

  • LocalStack version: latest
  • Running via: Docker / Compose / CLI
  • Infrastructure: Terraform / AWS CLI

🧑‍💻 Implementation

No response

Anything else?

No response

Activity

localstack-bot

localstack-bot commented on May 15, 2025

@localstack-bot
Collaborator

Welcome to LocalStack! Thanks for reporting your first issue and our team will be working towards fixing the issue for you or reach out for more background information. We recommend joining our Slack Community for real-time help and drop a message to LocalStack Support if you are a licensed user! If you are willing to contribute towards fixing this issue, please have a look at our contributing guidelines.

cloutierMat

cloutierMat commented on May 15, 2025

@cloutierMat
Contributor

Hi @pieronatan, thank you for your report of this bug in LocalStack.

I am trying to get a good understanding of your use case so I can get to the issuemore quickly. Can you tell me which integration you are using, as it sometimes impacts how ApiGw behaves with VTL template and overrides. Also, I assume you are using a lambda authorizer and using it's response in the authorizer context?

In AWS → returns HTTP 200.

#set($context.responseOverride.status = $statusCode) is not impacting the response, right? As this variable is only used in the response templates, not in the request templates? Did you experience something different?

requestOverride.querystring

I believe there may be a gap in our VTL implementation when attempting to use #set on a dict with dynamic assignment using [$var]. I will look into that one first as it seems to be the error you are experiencing given the following log

airspeed.operators.TemplateSyntaxError: line 5, column 13: expected assignment in set directive, got: ($context.requestOverride.querystrin ... ...

Please, let me know if I am missing anything.

self-assigned this
on May 15, 2025
added theissue type on May 15, 2025
added and removed
type: featureNew feature, or improvement to an existing feature
on May 15, 2025
pieronatan

pieronatan commented on May 15, 2025

@pieronatan
Author

I'm using a Lambda authorizer that returns custom metadata via the context object, including a statusCode. In my mapping template, I dynamically override the response status based on this value using context.responseOverride.status.

Attempts to hardcode the status code (e.g., setting it directly to a fixed value) resulted in errors.

#set($statusCode = 201)
#if($statusCode == 200)
    ##     Mapping the parameters from the request to the backend
    #foreach($param in $input.params().querystring.keySet())
        #if($foreach.hasNext) #end
    #end
    {
        "statusCode": 200,
        "message": "Valid scope found"
    }
#else
    #set($context.responseOverride.status = $statusCode)
    {
        "error": $context.authorizer.error
        "statusCode": $statusCode,
    }
#end
Non Gateway Exception raised: Error in template '<string>' at position 311-360 in expression: ($context.responseOverride.status = $statusCode)
 
 KeyError: 'responseOverride'
 Traceback (most recent call last):
   File "/opt/code/localstack/.venv/lib/python3.11/site-packages/airspeed/operators.py", line 370, in evaluate
     return self.evaluate_raw(*args)
            ^^^^^^^^^^^^^^^^^^^^^^^^
   File "/opt/code/localstack/.venv/lib/python3.11/site-packages/airspeed/operators.py", line 1089, in evaluate_raw
     cur = cur[term]
           ~~~^^^^^^
 KeyError: 'responseOverride'
 
 The above exception was the direct cause of the following exception:
 
 Traceback (most recent call last):
   File "/opt/code/localstack/.venv/lib/python3.11/site-packages/rolo/gateway/chain.py", line 166, in handle
     handler(self, self.context, response)
   File "/opt/code/localstack/localstack-core/localstack/services/apigateway/next_gen/execute_api/handlers/integration_request.py", line 122, in __call__
     body, request_override = self.render_request_template_mapping(
                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   File "/opt/code/localstack/localstack-core/localstack/services/apigateway/next_gen/execute_api/handlers/integration_request.py", line 194, in render_request_template_mapping
     body, request_override = self._vtl_template.render_request(
                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   File "/opt/code/localstack/localstack-core/localstack/services/apigateway/next_gen/execute_api/template_mapping.py", line 270, in render_request
     result = self.render_vtl(template=template.strip(), variables=variables_copy)
              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   File "/opt/code/localstack/localstack-core/localstack/utils/aws/templating.py", line 119, in render_vtl
     rendered_template = t.merge(namespace)
                         ^^^^^^^^^^^^^^^^^^
   File "/opt/code/localstack/.venv/lib/python3.11/site-packages/airspeed/operators.py", line 92, in merge
     self.merge_to(namespace, output, loader)
   File "/opt/code/localstack/.venv/lib/python3.11/site-packages/airspeed/operators.py", line 103, in merge_to
     self.root_element.evaluate(fileobj, namespace, loader)
   File "/opt/code/localstack/.venv/lib/python3.11/site-packages/airspeed/operators.py", line 370, in evaluate
     return self.evaluate_raw(*args)
            ^^^^^^^^^^^^^^^^^^^^^^^^
   File "/opt/code/localstack/.venv/lib/python3.11/site-packages/airspeed/operators.py", line 1359, in evaluate_raw
     self.block.evaluate(stream, namespace, loader)
   File "/opt/code/localstack/.venv/lib/python3.11/site-packages/airspeed/operators.py", line 370, in evaluate
     return self.evaluate_raw(*args)
            ^^^^^^^^^^^^^^^^^^^^^^^^
   File "/opt/code/localstack/.venv/lib/python3.11/site-packages/airspeed/operators.py", line 1394, in evaluate_raw
     child.evaluate(stream, namespace, loader)
   File "/opt/code/localstack/.venv/lib/python3.11/site-packages/airspeed/operators.py", line 370, in evaluate
     return self.evaluate_raw(*args)
            ^^^^^^^^^^^^^^^^^^^^^^^^
   File "/opt/code/localstack/.venv/lib/python3.11/site-packages/airspeed/operators.py", line 1064, in evaluate_raw
     self.else_block.evaluate(stream, namespace, loader)
   File "/opt/code/localstack/.venv/lib/python3.11/site-packages/airspeed/operators.py", line 370, in evaluate
     return self.evaluate_raw(*args)
            ^^^^^^^^^^^^^^^^^^^^^^^^
   File "/opt/code/localstack/.venv/lib/python3.11/site-packages/airspeed/operators.py", line 1394, in evaluate_raw
     child.evaluate(stream, namespace, loader)
   File "/opt/code/localstack/.venv/lib/python3.11/site-packages/airspeed/operators.py", line 370, in evaluate
     return self.evaluate_raw(*args)
            ^^^^^^^^^^^^^^^^^^^^^^^^
   File "/opt/code/localstack/.venv/lib/python3.11/site-packages/airspeed/operators.py", line 1294, in evaluate_raw
     self.assignment.evaluate(stream, namespace, loader)
   File "/opt/code/localstack/.venv/lib/python3.11/site-packages/airspeed/operators.py", line 375, in evaluate
     six.reraise(
   File "/opt/code/localstack/.venv/lib/python3.11/site-packages/six.py", line 723, in reraise
     raise value.with_traceback(tb)
   File "/opt/code/localstack/.venv/lib/python3.11/site-packages/airspeed/operators.py", line 370, in evaluate
     return self.evaluate_raw(*args)
            ^^^^^^^^^^^^^^^^^^^^^^^^
   File "/opt/code/localstack/.venv/lib/python3.11/site-packages/airspeed/operators.py", line 1089, in evaluate_raw
     cur = cur[term]
           ~~~^^^^^^
 airspeed.operators.TemplateExecutionError: Error in template '<string>' at position 311-360 in expression: ($context.responseOverride.status = $statusCode)
 
 KeyError: 'responseOverride'
cloutierMat

cloutierMat commented on May 15, 2025

@cloutierMat
Contributor

Thank you for the extra input I had time to run some quick test as well. I will keep you updated as the fix becomes available.

13 remaining items

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions

    feature request: Support of $context.requestOverride.status|querystring in apigateway · Issue #12621 · localstack/localstack