Send dict as response in Python Bottle with custom status code - python

import bottle
from bottle import route, run
#route('/', method='GET')
def homepage():
return {'foo' : 'bar'}
if __name__=='__main__':
bottle.debug(True)
run(host='0.0.0.0', port= 8080, reloader = True)
This config will return a json object representing the dict from homepage with HTTP status code 200. What should I do to return the same content but with, say, 202 status code?

You can set the response.status attribute:
from bottle import response
#route('/', method='GET')
def homepage():
response.status = 202
return {'foo' : 'bar'}

Related

Shopify Webhook HMAC Validation With Flask

I'm trying to verify that the Webhook received is coming from Shopify. They have this doc, but it doesn't work (getting type errors).
Here's what I have so far. It produces no errors, but the verify_webhook function always returns false.
from flask import Flask, request, abort
import hmac
import hashlib
import base64
app = Flask(__name__)
SECRET = '...'
def verify_webhook(data, hmac_header):
digest = hmac.new(SECRET.encode('utf-8'), data, hashlib.sha256).digest()
genHmac = base64.b64encode(digest)
return hmac.compare_digest(genHmac, hmac_header.encode('utf-8'))
#app.route('/', methods=['POST'])
def hello_world(request):
print('Received Webhook...')
data = request.get_data()
hmac_header = request.headers.get('X-Shopify-Hmac-SHA256')
verified = verify_webhook(data, hmac_header)
if not verified:
return 'Integrity of request compromised...', 401
print('Verified request...')
if __name__ == '__main__':
app.run()
What am I doing wrong?
Answer:
from flask import Flask, request, abort
import hmac
import hashlib
import base64
app = Flask(__name__)
SECRET = '...'
def verify_webhook(data, hmac_header):
digest = hmac.new(SECRET.encode('utf-8'), data, hashlib.sha256).digest()
genHmac = base64.b64encode(digest)
return hmac.compare_digest(genHmac, hmac_header.encode('utf-8'))
#app.route('/', methods=['POST'])
def hello_world(request):
print('Received Webhook...')
data = request.data # NOT request.get_data() !!!!!
hmac_header = request.headers.get('X-Shopify-Hmac-SHA256')
verified = verify_webhook(data, hmac_header)
if not verified:
return 'Integrity of request compromised...', 401
print('Verified request...')
if __name__ == '__main__':
app.run()
Issue was in the data = request.get_data() line.

Python Flask unable to get past CORS

I have the following script written in python
from flask import Flask, request, jsonify
from flask_cors import CORS, cross_origin
app = Flask(__name__)
CORS(app, resources=r'/chat', headers='Content-Type')
#app.route("/chat")
def chat():
print(request)
request.get_data()
data = json.loads(request.data)
response = chatbot.get_response(str(data['message']))
response_data = response.serialize()
response = jsonify({'data': response_data})
return response
app.run(host="0.0.0.0", port=8900, debug=True)
I am calling this API from a JavaScript frontend running on http://localhost:8080
I am using Google Chrome and get the following error
Access to XMLHttpRequest at 'http://localhost:8900/chat/' from origin 'http://localhost:8080' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
I also get the following the log message in the Python Console for each request
127.0.0.1 - - [19/Mar/2020 15:12:00] "?[33mOPTIONS /chat/ HTTP/1.1?[0m" 404 -
I am getting really frustrated because even if I change my code to
#app.route("/chat")
def chat():
print(request)
request.get_data()
data = json.loads(request.data)
response = chatbot.get_response(str(data['message']))
response_data = response.serialize()
response = jsonify({'data': response_data})
response.headers.add('Access-Control-Allow-Origin', '*')
response.headers.add('Access-Control-Allow-Headers', 'append,delete,entries,foreach,get,has,keys,set,values,Authorization')
response.headers.add('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,OPTIONS')
return response
I still get the same error.
Can you try setting the headers like this instead?
from flask import Flask, request, jsonify
from flask_cors import CORS, cross_origin
app = Flask(__name__)
CORS(app, resources=r'/chat', headers='Content-Type')
#app.route("/chat")
def chat():
print(request)
request.get_data()
data = json.loads(request.data)
response = chatbot.get_response(str(data['message']))
response_data = response.serialize()
response = jsonify({'data': response_data})
response.headers['Access-Control-Allow-Origin'] = '*'
response.headers['Access-Control-Allow-Headers'] = 'append,delete,entries,foreach,get,has,keys,set,values,Authorization'
response.headers['Access-Control-Allow-Methods'] = 'GET,PUT,POST,DELETE,OPTIONS'
return response
app.run(host="0.0.0.0", port=8900, debug=True)

Unittesting cherrypy webapp

I recently had to rewrite our rest api, and made the switch from Flask to Cherrypy (mostly due to Python 3 compatibility). But now I'm stuck trying to write my unit tests, Flask has a really nifty built-in test client, that you can use to sent fake requests to your application (without starting a server.) I can't find any similar functionality for Cherrypy, is there such functionality, or am I stuck starting a server and doing actual requests against it?
As far as I know, CherryPy doesn't indeed provide a facility for this type of testing (no running server). But it's fairly easy to do it nonetheless (though it relies on some of the internals of CherryPy).
Here's a simple showcase:
from StringIO import StringIO
import unittest
import urllib
import cherrypy
local = cherrypy.lib.httputil.Host('127.0.0.1', 50000, "")
remote = cherrypy.lib.httputil.Host('127.0.0.1', 50001, "")
class Root(object):
#cherrypy.expose
def index(self):
return "hello world"
#cherrypy.expose
def echo(self, msg):
return msg
def setUpModule():
cherrypy.config.update({'environment': "test_suite"})
# prevent the HTTP server from ever starting
cherrypy.server.unsubscribe()
cherrypy.tree.mount(Root(), '/')
cherrypy.engine.start()
setup_module = setUpModule
def tearDownModule():
cherrypy.engine.exit()
teardown_module = tearDownModule
class BaseCherryPyTestCase(unittest.TestCase):
def webapp_request(self, path='/', method='GET', **kwargs):
headers = [('Host', '127.0.0.1')]
qs = fd = None
if method in ['POST', 'PUT']:
qs = urllib.urlencode(kwargs)
headers.append(('content-type', 'application/x-www-form-urlencoded'))
headers.append(('content-length', '%d' % len(qs)))
fd = StringIO(qs)
qs = None
elif kwargs:
qs = urllib.urlencode(kwargs)
# Get our application and run the request against it
app = cherrypy.tree.apps['']
# Let's fake the local and remote addresses
# Let's also use a non-secure scheme: 'http'
request, response = app.get_serving(local, remote, 'http', 'HTTP/1.1')
try:
response = request.run(method, path, qs, 'HTTP/1.1', headers, fd)
finally:
if fd:
fd.close()
fd = None
if response.output_status.startswith('500'):
print response.body
raise AssertionError("Unexpected error")
# collapse the response into a bytestring
response.collapse_body()
return response
class TestCherryPyApp(BaseCherryPyTestCase):
def test_index(self):
response = self.webapp_request('/')
self.assertEqual(response.output_status, '200 OK')
# response body is wrapped into a list internally by CherryPy
self.assertEqual(response.body, ['hello world'])
def test_echo(self):
response = self.webapp_request('/echo', msg="hey there")
self.assertEqual(response.output_status, '200 OK')
self.assertEqual(response.body, ["hey there"])
response = self.webapp_request('/echo', method='POST', msg="hey there")
self.assertEqual(response.output_status, '200 OK')
self.assertEqual(response.body, ["hey there"])
if __name__ == '__main__':
unittest.main()
Edit, I've extended this answer as a CherryPy recipe.
It seems that there is an alternate way to perform unittest.
I just found and check the following recipe which works fine with cherrypy 3.5.
http://docs.cherrypy.org/en/latest/advanced.html#testing-your-application
import cherrypy
from cherrypy.test import helper
class SimpleCPTest(helper.CPWebCase):
def setup_server():
class Root(object):
#cherrypy.expose
def echo(self, message):
return message
cherrypy.tree.mount(Root())
setup_server = staticmethod(setup_server)
def test_message_should_be_returned_as_is(self):
self.getPage("/echo?message=Hello%20world")
self.assertStatus('200 OK')
self.assertHeader('Content-Type', 'text/html;charset=utf-8')
self.assertBody('Hello world')
def test_non_utf8_message_will_fail(self):
"""
CherryPy defaults to decode the query-string
using UTF-8, trying to send a query-string with
a different encoding will raise a 404 since
it considers it's a different URL.
"""
self.getPage("/echo?message=A+bient%F4t",
headers=[
('Accept-Charset', 'ISO-8859-1,utf-8'),
('Content-Type', 'text/html;charset=ISO-8859-1')
]
)
self.assertStatus('404 Not Found')
I found the answer from Sylvain Hellegouarch to be super helpful in figuring this out, but it uses Python 2. I adapted their answer to use Python 3:
import io
import unittest
import urllib
import urllib.parse
import cherrypy
from cherrypy.lib import httputil
local = httputil.Host('127.0.0.1', 50000, '')
remote = httputil.Host('127.0.0.1', 50001, '')
class Root(object):
#cherrypy.expose
def index(self):
return 'hello world'
#cherrypy.expose
def echo(self, msg):
return msg
def setUpModule():
cherrypy.config.update({'environment': 'test_suite'})
# prevent the HTTP server from ever starting
cherrypy.server.unsubscribe()
cherrypy.tree.mount(Root(), '/')
cherrypy.engine.start()
setup_module = setUpModule
def tearDownModule():
cherrypy.engine.exit()
teardown_module = tearDownModule
class BaseCherryPyTestCase(unittest.TestCase):
def webapp_request(self, path='/', method='GET', **kwargs):
headers = [('Host', '127.0.0.1')]
qs = fd = None
if method in ['POST', 'PUT']:
qs = urllib.parse.urlencode(kwargs)
headers.append(('content-type', 'application/x-www-form-urlencoded'))
headers.append(('content-length', f'{len(qs)}'))
fd = io.BytesIO(qs.encode())
qs = None
elif kwargs:
qs = urllib.parse.urlencode(kwargs)
# Get our application and run the request against it
app = cherrypy.tree.apps['']
# Let's fake the local and remote addresses
# Let's also use a non-secure scheme: 'http'
request, response = app.get_serving(local, remote, 'http', 'HTTP/1.1')
try:
response = request.run(method, path, qs, 'HTTP/1.1', headers, fd)
finally:
if fd:
fd.close()
fd = None
if response.output_status.startswith(b'500'):
print(response.body)
raise AssertionError('Unexpected error')
# collapse the response into a bytestring
response.collapse_body()
return response
class TestCherryPyApp(BaseCherryPyTestCase):
def test_index(self):
response = self.webapp_request('/')
self.assertEqual(response.output_status, b'200 OK')
# response body is wrapped into a list internally by CherryPy
self.assertEqual(response.body, [b'hello world'])
def test_echo(self):
response = self.webapp_request('/echo', msg='hey there')
self.assertEqual(response.output_status, b'200 OK')
self.assertEqual(response.body, [b'hey there'])
response = self.webapp_request('/echo', method='POST', msg='hey there')
self.assertEqual(response.output_status, b'200 OK')
self.assertEqual(response.body, [b'hey there'])

How do I simulate an AJAX request with Flask test client?

Testing Flask applications is done with:
# main.py
from flask import Flask, request
app = flask.Flask(__name__)
#app.route('/')
def index():
s = 'Hello world!', 'AJAX Request: {0}'.format(request.is_xhr)
print s
return s
if __name__ == '__main__':
app.run()
Then here is my test script:
# test_script.py
import main
import unittest
class Case(unittest.TestCase):
def test_index():
tester = app.test_client()
rv = tester.get('/')
assert 'Hello world!' in rv.data
if __name__ == '__main__':
unittest.main()
In the test output, I'll get:
Hello world! AJAX Request: False
Question
How do I test my app with AJAX requests?
Try this:-
def test_index():
tester = app.test_client()
response = tester.get('/', headers=[('X-Requested-With', 'XMLHttpRequest')])
assert 'Hello world!' in response.data
import json
def test_index():
data = json.dumps({})
client = app.test_client()
headers = {
'Content-Type': 'application/json',
}
response = client.post('/', data=data, headers=headers)
data = json.loads(response.data)
assert data
`

Google App Engine HTTP information being printed somehow

I'm just wanting to return a JSON object, but HTTP information is being printed below it. I'm using Google App Engine and https://github.com/simplegeo/python-oauth2
#!/usr/bin/env python
from google.appengine.ext import webapp
from google.appengine.ext.webapp import util
from django.utils import simplejson as json
import oauth2 as oauth
import cgi
class MainHandler(webapp.RequestHandler):
def get(self):
consumer = oauth.Consumer(key="xxx",
secret="xxx")
request_token_url = "xxx"
client = oauth.Client(consumer)
resp, content = client.request(request_token_url, "POST")
if resp['status'] != '200':
raise Exception("Invalid response %s." % resp['status'])
request_token = dict(cgi.parse_qsl(content))
print
print json.dumps({"oauth_token": request_token['oauth_token'], "oauth_token_secret": request_token['oauth_token_secret']})
def main():
application = webapp.WSGIApplication([('/', MainHandler)],
debug=True)
util.run_wsgi_app(application)
if __name__ == '__main__':
main()
Add the proper Content-Type and switch to self.response.out.write
self.response.headers['Content-Type'] = 'application/json'
self.response.out.write(data)
Instead of print use self.response:
self.response.out.write("Some Text")
I suppose that the RequestHandler automatically prints a default HTTP header and sends it if nothing is written to the response.out stream.
If you only want to send JSON data you can set the "Content-Type" header information to "application/json".

Categories

Resources