How to implement multiple POST methods in CherryPy - cherrypy

I am new to cherryPy and I am working on communicating the GUI with Python functions, for it I am using CherryPy. I have followed this cherryPy tutorial. In that the POST method don't do much just return some string, but in my case there can be many functions which will communicate with GUI using the POST. I tried this:
#cherrypy.expose
class StringGeneratorWebService(object):
#cherrypy.tools.accept(media='text/plain')
def GET(self):
return cherrypy.session['mystring']
def POST(self, counter,param):
if counter == 1:
function1(param) # call a python function
elif counter == 2:
function2(param)
elif counter == 3:
function3(param)
def PUT(self, another_string):
cherrypy.session['mystring'] = another_string
def DELETE(self):
cherrypy.session.pop('mystring', None)
In above code in POST method, the counter and Param are parameters from the AJAX request. According to the counter value I am calling the respective function. The Param can be a big JSON document. The above code works but this is very crude way to do this, so is there other way which is a good coding practice?

The documentation is a little confusing, but you only need to implement the GET/POST Python methods if you want CherryPy to call different functions for you based on the HTTP method. If you don't care about GET requests on your POST URLs you can just use the #cherrypy.expose pattern.
If you look at the tutorial source for forms there's this helpful bit about exposing POST methods:
[Using HTTP POST method] would not change your application’s exposed method because CherryPy handles both the same way and uses the exposed’s handler parameters to deal with the query-string (key, value) pairs.
Modifying the handler to include the method makes this clear:
class StringGenerator(object):
#cherrypy.expose
def generate(self, length=8):
return cherrypy.request.method + ' ' + ''.join(random.sample(string.hexdigits, int(length)))
Now I can use curl make a GET then a POST request:
$ curl "http://example.com:8888/generate?length=8" # does a GET
GET 78A35e4f
$ curl "http://example.com:8888/generate" --data "length=8" # does a POST
POST 14d0D92c

Related

Flask App Simulating blocking API to abstract from web hook based callback

I have Angular 8 web app. It needs to send some data for analysis to python flask App. This flask App will send it to 3rd party service and get response through webhook.
My need is to provide a clean interface to the client so that there is no need to provide webhook from client.
Hence I am trying to initiate a request from Flask app, wait until I get data from webhook and then return.
Here is the code.
#In autoscaled micro-service this will not work. Right now, the scaling is manual and set to 1 instance
#Hence keeping this sliding window list in RAM is okay.
reqSlidingWindow =[]
#app.route('/handlerequest',methods = ['POST'])
def Process_client_request_and_respond(param1,param2,param3):
#payload code removed
#CORS header part removed
querystring={APIKey, 'https://mysvc.mycloud.com/postthirdpartyresponsehook'}
response = requests.post(thirdpartyurl, json=payload, headers=headers, params=querystring)
if(response.status_code == SUCCESS):
respdata = response.json()
requestId = respdata["request_id"]
requestobject = {}
requestobject['requestId'] = requestId
reqSlidingWindow.append(requestobject)
#Now wait for the response to arrive through webhook
#Keep checking the list if reqRecord["AllAnalysisDoneFlag"] is set to True.
#If set, read reqRecord["AnalysisResult"] = jsondata
jsondata = None
while jsondata is None:
time.sleep(2)
for reqRecord in reqSlidingWindow:
if(reqRecord["requestId"] == da_analysis_req_Id ):
print("Found matching req id in req list. Checking if analysis is done.")
print(reqRecord)
if(reqRecord["AllAnalysisDoneFlag"] == True):
jsondata = reqRecord["AnalysisResult"]
return jsonify({"AnalysisResult": "Success", "AnalysisData":jsondata})
#app.route('/webhookforresponse',methods = ['POST'])
def process_thirdparty_svc_response(reqIdinResp):
print(request.data)
print("response receieved at")
data = request.data.decode('utf-8')
jsondata = json.loads(data)
#
for reqRecord in reqSlidingWindow:
#print("In loop. current analysis type" + reqRecord["AnalysisType"] )
if(reqRecord["requestId"] == reqIdinResp ):
reqRecord["AllAnalysisDoneFlag"] = True
reqRecord["AnalysisResult"] = jsondata
return
I'm trying to maintain sliding window of requests in list. Upon the
Observations so far:
First, this does not work. The function of 'webhookforresponse' does not seem to run until my request function comes out. i.e. my while() loop appears to block everything though I have a time.sleep(). My assumption is that flask framework would ensure that callback is called since sleep in another 'route' gives it adequate time and internally flask would be multithreaded?
I tried running python threads for the sliding window data structure and also used RLocks. This does not alter behavior. I have not tried flask specific threading.
Questions:
What is the right architecture of the above need with flask? I need clean REST interface without callback for angular client. Everything else can change.
If the above code to be used, what changes should I make? Is threading required at all?
Though I can use database and then pick from there, it still requires polling the sliding window.
Should I use multithreading specific to flask? Is there any specific example with skeletal design, threading library choices?
Please suggest the right way to proceed to achieve abstract REST API for angular client which hides the back end callbacks and other complexities.

With Flask-Restplus how to create a POST api without making the URL same with GET

I'm new to Flask and Flask-RestPlus. I'm creating a web api where I want keep my POST urls different from the GET urls which are visible in Swagger. For example in Flask-Restplus
#api.route('/my_api/<int:id>')
class SavingsModeAction(Resource):
#api.expect(MyApiModel)
def post(self):
pass #my code goes here
def get(self, id):
pass #my code goes here
So in swagger for the both apis url would look like
GET: /my_api/{id}
POST: /my_api/{id}
But so far I have absolutely no use of {id} part in my post api and it perhaps creates a bit of confusion for an user whether to update an existing record or to create a new, however the purpose of the api is just to create.
It will be better to use query params
like GET: /my_api?id=
your above code will be like
from flask import request
#api.route('/my_api')
class SavingsModeAction(Resource):
#api.expect(MyApiModel)
def post(self):
...
def get(self):
_id = request.args.get("_id", type=int)
...

How to get resource path in flask-RESTPlus?

I am fairly new at working with flask and flask-RESTPlus. I have the following and it is not clear how can I determine which path was used in the get request?
ns = api.namespace('sample', description='get stuff')
#ns.route(
'/resource-settings/<string:address>',
'/unit-settings/<string:address>',
'/resource-proposals/<string:address>',
'/unit-proposals/<string:address>')
#ns.param('address', 'The address to decode')
class Decode(Resource):
#ns.doc(id='Get the decoded result of a block address')
def get(self, address):
# How do I know what get path was called?
pass
A better solution would be to use the request context. To get the full path, you can do:
from flask import request
def get(self, address):
# How do I know what get path was called?
print(request.full_path)
Through lot's of digging I found that url_for in flask import.
Still feels a bit wonky but I can create a fully qualified link with:
result = api.base_url + url_for('resource-settings', address=id)
So this works and I get the desired results.

Reading POST data - CherryPy web-framework

I'm new with CherryPy web-framework. I would like to know how can
I read POST data that was delivered via HTTP request's body .
Thanks,
Gabriel.
You can either read the body of the request with cherrypy.request.body, cherrypy.request.params or if you use the default handler then, the distinction between GET and POST values is abstracted by cherrypy and you can get the values directly from the arguments:
#cherrypy.expose
def index(self, name, age):
return "My name is %s and age is %s" % (name, age)
Your POST request must have to provide the values for name and age on the traditional forms submission.
If you are planning on using json, then use the cherrypy.tools.json_in decorator and read the cherrypy.request.json property. http://docs.cherrypy.org/en/latest/basics.html#dealing-with-json
If you are using the MethodDispatcher, then there is another way to do it: http://docs.cherrypy.org/en/latest/tutorials.html#tutorial-7-give-us-a-rest
Maybe these posts might help you:
http://blog.joel.mx/posts/cherrypy-101
http://blog.joel.mx/posts/cherrypy-101-method-dispatcher
Cherrypy handles both get and post in a similar way by passing them into the function or method that is handling the request. A good example is located at tut03_get_and_post.py in the tutorial folder within the cherrypy package.
Here is a small portion that specifically speaks to your question...
#cherrypy.expose
def greetUser(self, name=None):
# CherryPy passes all GET and POST variables as method parameters.
# It doesn't make a difference where the variables come from, how
# large their contents are, and so on.

bottle httprequest object manual update

Just yesterday got that I can't use one function that would return one template depending on cookies, and wich would be called by different methods of different routes. The reason is all the response.set_cookie() are not applied to main Bottle object HTTPResponse before the method finishes serving current route. So the question is there a way to explicitly cast application of all the changes to HTTPResponse object, so i could avoid passing complex structures to subroutines and etc.
Thank you for help!
UPD: there is a response.set_cookie('temp', 'sampletext') line for example. And then i am calling subroutine and it calls another one and so on. So In each of them i won't have request.get_cookie('temp') returning 'sampletext'. Because changes to cookies wasn't applied yet. There are in the Bottle.py code you can find following code:
class HTTPResponse(Response, BottleException):
def __init__(self, body='', status=None, headers=None, **more_headers):
super(HTTPResponse, self).__init__(body, status, headers, **more_headers)
def apply(self, response):
response._status_code = self._status_code
response._status_line = self._status_line
response._headers = self._headers
response._cookies = self._cookies
response.body = self.body
that seems to be executing once per request and changes from httpresponse objects are appliied to the response object only on finish of the rout's serving method termination.
I am asking if there is a way to apply changes to response object manually, during the route's serving method evaluation.
I am asking if there is a way to apply changes to response object manually, during the route's serving method evaluation.
No.
I'm not completely sure, but it sounds like you just want to store some state during a request.
The mechanism for this is to simply set attributes on the request object. E.g.
#route(...)
def index_page():
...
request.mydata = 'hello'
...
This is completely independent of cookies. If you need both, just set both; one on the request object and the other on the response.

Resources