openfaas / python-flask-template

HTTP and Flask-based OpenFaaS templates for Python 3
MIT License
85 stars 86 forks source link

Error with Twilio example #4

Closed lachie83 closed 5 years ago

lachie83 commented 6 years ago

Reported as: Not receiving request body in function handler

I'm trying to test the following python flask code.

https://github.com/chzbrgr71/kube-con-2018/blob/master/open-faas/sms-ratings/sms-ratings/handler.py

I've tried printing the request body and it appears to be empty. What am I doing wrong?

Here's the error I'm seeing

Traceback (most recent call last):
  File "/usr/local/lib/python2.7/site-packages/flask/app.py", line 2292, in wsgi_app
    response = self.full_dispatch_request()
  File "/usr/local/lib/python2
2018/07/16 06:51:23 stderr: .7/site-packages/flask/app.py", line 1815, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File "/usr/local/lib/python2.7/site-packages/flask/app.py", line 1718, in handle_user_exception
    reraise(exc_type, exc_value, tb)
  File "/usr/l
2018/07/16 06:51:23 stderr: ocal/lib/python2.7/site-packages/flask/app.py", line 1813, in full_dispatch_request
    rv = self.dispatch_request()
  File "/usr/local/lib/python2.7/site-packages/flask/app.py", line 1799, in dispatch_request
    return self.view_functions[rule.endpoint](
2018/07/16 06:51:23 stderr: **req.view_args)
  File "index.py", line 11, in main_route
    ret = handler.handle(request.get_data())
  File "/root/function/handler.py", line 10, in handle
    msgBody = req.values.get("Body")
AttributeError: 'str' object has no attribute 'values'

I've also used HTTP GET to confirm I'm seeing the parameters correctly sent in the URL.

Here's a scrubbed set of parameters from the request.

ApiVersion=2010-04-01&SmsSid=<>&SmsStatus=<>&SmsMessageSid=<>&NumSegments=1&From=<>&ToState=OR&MessageSid=<>&AccountSid=<>&ToZip=<>&FromCountry=US&ToCity=<>&FromCity=<>&To=<>&FromZip=<>&Body=<>&ToCountry=US&FromState=<>&NumMedia=0
alexellis commented 6 years ago

Hi, this is not the conventional Python template. Curious as to what made you pick this one for your function? It looks like you're invoking through function with multi-part form data?

Can you show the invocation command for this?

alexellis commented 6 years ago

My best guess is that Brian Redmond edited the template then didn't commit the changes back into GitHub or raise a PR to this template.

Here's why I think that:

https://github.com/chzbrgr71/kube-con-2018/blob/master/open-faas/sms-ratings/sms-ratings/handler.py#L10

    msgBody = req.values.get('Body')

In this context req is always a string, which if is in a JSON format can be parsed and then accessed / indexed. Brian is indexing the string directly trying to access the "values" property which clearly won't exist.

Ping @chzbrgr71

The other thing I would note is in the sample .yml file only one environmental variable is given: COG_SERVICES_KEY, yet the code references other environmental variables which won't be provided in that YAML file.

https://github.com/chzbrgr71/kube-con-2018/blob/master/open-faas/sms-ratings/sms-ratings-replace.yml#L11

The README file is lacking some steps including the one that you've guessed about faas-cli template pull to fetch in the incubator Python template.

I hope this helps @lachie83 ..

Alex

alexellis commented 6 years ago

cc @viveksyngh

chzbrgr71 commented 6 years ago

Hope I can help here. First off, I regret using Python for this. :-) Had all kinds of issues and was forced to do some weird things with openfaas. But in the end, this code should work.

Unfortunately, Twilio sends a payload that is not JSON. It is possible that the message from Twilio is an error and not the actual payload. You can check the logs on the Twilio side and validate that the message came across correctly. I bet there is an error or a clue in there.

I assume you have setup the webhook on the Twilio side or this would not have fired.

There are a couple missing pieces in the YAML file. You need to set the API_URL for the ratings microservice and the COG_SERVICES_URL though I still think this error occurs before you get to that line of code.

alexellis commented 6 years ago

Hi Brian,

Thanks for coming over to look at this.

Generally the body is always a string / bytes that we parse into a JSON struct or use as-is.

In this particular template, maybe it just worked. Here's the underlying code:

https://github.com/openfaas-incubator/python-flask-template/blob/master/template/python27-flask/index.py#L11

@chzbrgr71 API_URL should be added to your sample YAML file, you could also rename it to stack.yml so no -f flag is needed.

I'd also suggest adding a quick README explaining how to deploy the function and pull in the template.

Alex

lachie83 commented 6 years ago

Thanks @alexellis. Thank helps my understanding and I actually wonder how this was working in the first place. Let me try loading the string into JSON then parsing.

alexellis commented 6 years ago

I wonder if the example came from here? https://www.twilio.com/docs/sms/tutorials/how-to-receive-and-reply-python

Trying to see what the RAW format is, it looks a bit like a query-string.

alexellis commented 6 years ago

OK I looked into some examples and found they just send a single string in the style of a query-string:

example:

$ faas deploy --name echo --image functions/alpine:latest --fprocess=cat
$ curl http://127.0.0.1:8080/function/env -i --data-urlencode from=alex --data-urlencode to=azure ; echo
HTTP/1.1 200 OK
Content-Length: 18
Content-Type: application/x-www-form-urlencoded
Date: Mon, 16 Jul 2018 16:31:06 GMT
X-Call-Id: 1da122a6-a202-4f3a-928b-498982ed4e63
X-Duration-Seconds: 0.010683
X-Start-Time: 1531758666180799304

from=alex&to=azure

So if the underlying flask framework should decode this automatically, if it doesn't you can parse it with the querystring library.

Apparently they support C#/Java/Node/PHP/Ruby too.

alexellis commented 5 years ago

Derek close