how to handle kwargs when doing lazily loading in flask - python-3.x

i m trying to do lazy loading of python method in flask by using app.add_url_rule
I have url rule created by parsing each python file and getting method_name/argument1/argument2 etc...
But there are kwargs in some method and how do i handle kwargs in my flask endpoint while doing lazy loading, Here is example -
def create_user(self, username, userid, **kwargs):
*Method implementation*
url_rule in above case is
/create_user/<username>/<userid>
if i access http://127.0.0.1:5000/abc/1212/company=new
I get
Not Found The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again.
Any idea how to deal with this issue.

You want your company variable to be a URL parameter and not a part of the URL itself:
http://127.0.0.1:5000/abc/1212?company=new
Then in your app you access them from the flask.request.args dict:
#app.route('/<username>/<userid>')
def create_user(self, username, userid):
url_params = request.args
company = url_params.get('company', 'default_if_none')
...

Related

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)
...

Request using trio asks returns a different response than with requests and aiohttp

Right, hello, so I'm trying to implement opticard (loyality card services) with my webapp using trio and asks (https://asks.readthedocs.io/).
So I'd like to send a request to their inquiry api:
Here goes using requests:
import requests
r = requests.post("https://merchant.opticard.com/public/do_inquiry.asp", data={'company_id':'Dt', 'FirstCardNum1':'foo', 'g-recaptcha-response':'foo','submit1':'Submit'})
This will return "Invalid ReCaptcha" and this is normal, and what I want
Same thing using aiohttp:
import asyncio
import aiohttp
async def fetch(session, url):
async with session.post(url, data={'company_id':'Dt', 'FirstCardNum1':'foo', 'g-recaptcha-response':'foo','submit1':'Submit'} ) as response:
return await response.text()
async def main():
async with aiohttp.ClientSession() as session:
html = await fetch(session, 'https://merchant.opticard.com/public/do_inquiry.asp')
print(html)
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
Now this also returns "Invalid ReCaptcha", so that's all nice and good.
However now, using trio/asks:
import asks
import trio
async def example():
r = await asks.post('https://merchant.opticard.com/public/do_inquiry.asp', data={'company_id':'Dt', 'FirstCardNum1':'foo', 'g-recaptcha-response':'foo','submit1':'Submit'})
print(r.text)
trio.run(example)
This returns a completely different response with 'Your session has expired to protect your account. Please login again.', this error/message can be accessed normally when inputting an invalid url such as 'https://merchant.opticard.com/do_inquiry.asp' instead of 'https://merchant.opticard.com/public/do_inquiry.asp'.
I have no idea where this error is coming from, I tried setting headers, cookies, encoding, nothing seems to make it work. I tried replicating the issue, but the only way I managed to replicate the result with aiohttp and requests is by setting an incorrect url like 'https://merchant.opticard.com/do_inquiry.asp' instead of 'https://merchant.opticard.com/public/do_inquiry.asp'.
This must be an issue from asks, maybe due to encoding or formatting, but I've been using asks for over a year and never had an issue where a simple post request with data would return differently on asks compared to everywhere else. And I'm baffled as I can't understand why this is happening, it couldn't possibly be a formatting error on asks' part because if so how come this is the first time something like this has ever happened after using it for over a year?
This is a bug how asks handles redirection when a non-standard location is received.
The server returns a 302 redirection with Location: inquiry.asp?... while asks expects it to be a full URL. You may want to file a bug report to asks.
How did I find this? A good way to go is to use a proxy (e.g. mitmproxy) to inspect the traffic. However asks doesn't support proxies. So I turned to wireshark instead and use a program to extract TLS keys so wireshark can decrypt the traffic.

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.

Flask - url_for automatically escapes '=' to '%3D'

So.. I'm having some issues with Flask's url_for . The code still works.. but when users navigate to a link that was generated by url_for the link looks bad in the address bar.
Namely, I have a decorated view function as follows:
#app.route("/")
#app.route("/page=<int:number")
def index(number=0):
return "Index Page: {}".format(number)
This all works fine except when I try to generate a url for that route. Calling:
url_for("index", number=10)
Yields: domain.tld:80/page%3D10
Is there any way to circumvent this issue? I'd like for '=' to be returned instead of '%3D' when it's built into the route itself.
I only noticed it was doing this when I was testing it in an assert and discovered that the routes were ending up different from what I expected them to be.
At the moment, I have my test case circumvent the issue by using urllib.parse.unquote to fix the url for testing purposes. I could probably just do that for all urls since I won't have any user input to worry about those causing problems.. but it's there for a reason so.... :P
One option you have is to not build the parameter in to the route itself, but use query parameters instead:
from flask import Flask, render_template, request, url_for
app = Flask(__name__)
#app.route("/")
def index():
page = request.args.get('page', 0, type=int)
print(url_for("index", page=10)) # yields /?page=10
return "Index Page: {}".format(page)
app.run(debug=True)
My making use of query parameters for the route, you avoid the issue of Flask encoding the = sign in the route definition.

Resources