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

Feature request: Support Lambda Function Urls in local start-api #4299

Open
lambrospetrou opened this issue Oct 12, 2022 · 15 comments
Open

Feature request: Support Lambda Function Urls in local start-api #4299

lambrospetrou opened this issue Oct 12, 2022 · 15 comments
Labels
maintainer/need-followup stage/pm-review Waiting for review by our Product Manager, please don't work on this yet type/feature Feature request

Comments

@lambrospetrou
Copy link

lambrospetrou commented Oct 12, 2022

Describe your idea/feature/enhancement

With the addition of Lambda Function URLs, we don't need API Gateway for full APIs. However, the sam local start-api command does not support that yet, and fails with the error that no API exists.

An example of such SAM template can be found in https://github.com/lambrospetrou/aws-playground/blob/master/aws-lambda-url-and-fly-golang-proxy/aws-iac/sam-template.yml. Relevant excerpt below:

Resources:
  HelloFunction:
    Type: AWS::Serverless::Function
    Properties:
      CodeUri: ../build/handler.zip
      Handler: handler
      Runtime: go1.x
      MemorySize: 512
      FunctionUrlConfig:
        AuthType: NONE

Proposal

Ideally, the cli should be able to add the Function URLs defined as part of the expose API, or even expose them in different ports if we want them separate from a potential API Gateway definition.

Things to consider:

  1. Will this require any updates to the SAM Spec. It shouldn't.
@lambrospetrou lambrospetrou added stage/needs-triage Automatically applied to new issues and PRs, indicating they haven't been looked at. type/feature Feature request labels Oct 12, 2022
@lucashuy
Copy link
Contributor

Thanks for raising this feature request! I'll bring this up with the team to discuss about next steps

@lucashuy lucashuy added stage/pm-review Waiting for review by our Product Manager, please don't work on this yet and removed stage/needs-triage Automatically applied to new issues and PRs, indicating they haven't been looked at. labels Oct 13, 2022
@jamalmoir
Copy link

This is a pretty big blocker for me. Not being able to develop locally without deploying test functions is very annoying.

Great to hear it's being looked into.

@JP-tech-sh
Copy link

This could be a really nice feature to implement, I tried to use a local template file with a dummy api gateway event, this may work for some but the main problem is the Payload format version, in the case of a regular lambda with lambda url function, the version is 2.0 and when executing sam local start-api the only version available is 1.0, there should not be many changes requierd to make this work, adding support for reading the lambda url details form the template file and using payload v2.0 when this is detected, I'll be happy to help with this.

@praneetap
Copy link
Contributor

@JP-tech-sh thanks for offering to contribute! Would you be willing to write up a design proposal in this issue? Once we have clarity on design you can open a PR.

@valerena
Copy link
Contributor

I think one difference between Function URLs and API Gateway is that functions URLs are all served directly at the root / (The difference between multiple functions is just the domain).

What would be a good experience for you when you have multiple functions with URLs on the same template? Options I can think of:

  • To make only one function URL work, assuming users will want to try only one at a time.
  • To have a made-up path that's different for each function (but that will be different than the actual path when deployed to Lambda (which is just /))
  • To expose different functions URLs on different ports (What ports? How many should be supported?)
  • Some other suggestion?

@lambrospetrou
Copy link
Author

As a user I would prefer to have a different port per Lambda function URL, and APIGW. Having different prefixes in the path would work if all you do is call it once, but when pointing to the API from another application (e.g. a UI) where the paths are assuming to be at the / of the endpoint then it makes this awkward.

Also, the user should be able to specify by resource name/id the lambda function to start so that you only start that one, which I think is a behavior that already exists for the single invocation functionality.

@kulanjith-deelaka-appspotr

this may work for some but the main problem is the Payload format version, in the case of a regular lambda with lambda url function, the version is 2.0 and when executing sam local start-api the only version available is 1.0

@JP-tech-sh It's a really valid point that you have raised here. This is the major issue that impacts usability, hopefully the payload version is an easy fix, this would make it bearable for the time being and ultimately hope this Feature Request goes through.

@AxelJunker
Copy link

I would also like this feature!

As a workaround I use sam local start-lambda, then invoke the function (which has the FunctionUrlConfig field in the template) with:

curl -XPOST "http://127.0.0.1:3001/2015-03-31/functions/MyFunction/invocations" -d '{"payload":"hello world!"}'

No idea why 2015-03-31 is needed (it doesn't work when I change it).

Sources:
https://www.reddit.com/r/aws/comments/x2i1x2/comment/imjjuhd/?utm_source=share&utm_medium=web2x&context=3
https://hub.docker.com/r/amazon/aws-lambda-java

@sayandcode
Copy link

sayandcode commented Jan 27, 2023

I would also like this feature!

As a workaround I use sam local start-lambda, then invoke the function (which has the FunctionUrlConfig field in the template) with:

curl -XPOST "http://127.0.0.1:3001/2015-03-31/functions/MyFunction/invocations" -d '{"payload":"hello world!"}'

No idea why 2015-03-31 is needed (it doesn't work when I change it).

Sources: https://www.reddit.com/r/aws/comments/x2i1x2/comment/imjjuhd/?utm_source=share&utm_medium=web2x&context=3 https://hub.docker.com/r/amazon/aws-lambda-java

Thanks a lot for that workaround! This solution looks good enough for me to run on my local. Do you know how to get methods other than POST to work?

@cShirley14
Copy link

I would also like this feature!

As a workaround I use sam local start-lambda, then invoke the function (which has the FunctionUrlConfig field in the template) with:

curl -XPOST "http://127.0.0.1:3001/2015-03-31/functions/MyFunction/invocations" -d '{"payload":"hello world!"}'

No idea why 2015-03-31 is needed (it doesn't work when I change it).

Sources: https://www.reddit.com/r/aws/comments/x2i1x2/comment/imjjuhd/?utm_source=share&utm_medium=web2x&context=3 https://hub.docker.com/r/amazon/aws-lambda-java

FWIW the date 2015-03-31 is AWS's way of versioning (totally random, but they articulate this in different language docs PHP , Node etc...

@darrenkidd
Copy link

darrenkidd commented Jun 19, 2023

Extending @AxelJunker's method, if you used the sam CLI and a template to build your solution you probably have an events/event.json you can play with.

I found this worked quite well to invoke the lambda directly (my lambda returns HTML):

$ curl -XPOST "http://127.0.0.1:3001/2015-03-31/functions/MyFunction/invocations" -d @events/event.json
{"statusCode": 200, "headers": {"Content-Type": "text/html"}, "body": "..."}

However, I couldn't execute that in the browser. So I threw together a quick Flask app to forward requests so I could try it locally. Essentially this is answering @sayandcode's question as well.

requirements.txt

flask
requests

app.py

import os
import requests

from flask import Flask, request, Response

LAMBDA_HOST = os.getenv('LAMBDA_HOST', '127.0.0.1:3001')
TARGET_URL = 'http://{}/2015-03-31/functions/{}/invocations'

app = Flask(__name__)

@app.route('/<function>', methods=['GET'])
def forward_request(function):
    url = TARGET_URL.format(LAMBDA_HOST, function)
    payload = {
        'httpMethod': 'GET',
        'queryStringParameters': request.args.to_dict(),
    }
    response = requests.post(url, json=payload)
    response.raise_for_status()
    lambda_response = response.json()
    return Response(lambda_response['body'], status=lambda_response['statusCode'], headers=lambda_response['headers'])

There's way more you can do with the payload etc. but this was all I really needed. I just started everything then went in to the browser and hit http://127.0.0.1:5000/MyFunction?a=b as a test.

Forwarder:

$ flask run
...
127.0.0.1 - - [19/Jun/2023 21:42:10] "GET /MyFunction?a=b HTTP/1.1" 200 -

Lambda:

$ sam local start-lambda --force-image-build
...
START RequestId: d88b7596-5bd8-4be0-9703-3249c6645e4d Version: $LATEST
{'httpMethod': 'GET', 'queryStringParameters': {'a': 'b'}}
END RequestId: d88b7596-5bd8-4be0-9703-3249c6645e4d
REPORT RequestId: d88b7596-5bd8-4be0-9703-3249c6645e4d  Init Duration: 0.22 ms  Duration: 182.33 ms     Billed Duration: 183 ms Memory Size: 128 MB     Max Memory Used: 128 MB
2023-06-19 21:41:31 127.0.0.1 - - [19/Jun/2023 21:41:31] "POST /2015-03-31/functions/MyFunction/invocations HTTP/1.1" 200 -

HTH

It'd definitely be much nicer to have this built in somehow, however. I'll have a look at the code at some point and see if there's any obvious way of integrating it.

@pharsi
Copy link

pharsi commented Nov 10, 2023

I ran into this right now, using Lambda Function integrated with REST API GW. Will share a template that's causing this as I get time.

The issue is, when I deploy Lambda to AWS using sam template the payload format version is 2.0 while on local debugging setup the payload format version is 2.0, this is causing some nightmares in local debugging. For instance, pathParameters and rawQueryString are different in both format versions

@leehagoodjames
Copy link

I am also running into this now. I tried the Python Flask app and it works for making a request (with query parameters) directly from the browser (and curl), but I am getting a cors error when my local dev setup calls the API

@leehagoodjames
Copy link

leehagoodjames commented Nov 10, 2023

I managed to fix the CORS issue by rewriting the last line in app.py to merge the lambda headers dictionariy with {'Access-Control-Allow-Origin': '*'} via the following:

return Response(lambda_response['body'], status=lambda_response['statusCode'], headers=lambda_response['headers'] | {'Access-Control-Allow-Origin': '*'})

@faermanj
Copy link

This would be super helpful, for some bizarre reason our API Gateway integration just stopped working and we would love to use anything else.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
maintainer/need-followup stage/pm-review Waiting for review by our Product Manager, please don't work on this yet type/feature Feature request
Projects
None yet
Development

No branches or pull requests