Pass filepath as parameter to a URL in FLASK(Python) - python-3.x

I want to build an api which accepts a parameter from the user which is a filepath and then process the file given in that path. The file to be processed is already in the server where the api will be running.
As of now, I have written an api where I have hardcoded the filepath in my code which runs the api. Now, I want to configure my api in such a way that accepts a filepath from the user. My api should accept the path as a parameter and process the file that has been given in the path.
The api code is as follows:
The convert function returns the category of the file.
import ectd
from ectd import convert
from flask import Flask, request
from flask_restful import Resource, Api
#from flask.views import MethodView
app = Flask(__name__)
api = Api(app)
#convert(r'D:\files\67cecf40-71cf-4fc4-82e1-696ca41a9fba.pdf')
class ectdtext(Resource):
def get(self, result):
return {'data': ectd.convert(result)}
#api.add_resource(ectdtext, '/ectd/<result>')
categories=convert(r'D:\files\6628cb99-a400-4821-8b13-aa4744bd1286.pdf')
#app.route('/')
def returnResult():
return categories
if __name__ == '__main__':
app.run(host="0.0.0.0", port=5000)
So, I want to make changes to this code to accept a parameter from the user which will be a filepath and the convert function will process that filepath. I want to know how to make my api accept a filepath parameter from the user.
Trial with requests.args.get:
import ectd
from ectd import convert
from flask import Flask, request
from flask_restful import Resource, Api
#from flask.views import MethodView
app = Flask(__name__)
api = Api(app)
#convert(r'D:\files\67cecf40-71cf-4fc4-82e1-696ca41a9fba.pdf')
class ectdtext(Resource):
def get(self, result):
return {'data': ectd.convert(result)}
#api.add_resource(ectdtext, '/ectd/<result>')
#app.route('/')
def returnResult():
categories=convert(r'D:\files\'.format(request.args.get('categories')))
return categories
if __name__ == '__main__':
app.run(host="0.0.0.0", port=5000)
results in error :
"RuntimeError: Working outside of request context.
This typically means that you attempted to use functionality that needed
an active HTTP request. Consult the documentation on testing for
information about how to avoid this problem."
PRESENT SCENARIO:
I am able to post a filepath to the url. My question is now how do I use this posted url with filepath in my code to trigger my function that takes in the filepath and processes the file. Code to post the filepath:
import ectd
from ectd import convert
from flask import Flask, request
from flask_restful import Resource, Api
#from flask.views import MethodView
app = Flask(__name__)
api = Api(app)
class ectdtext(Resource):
def get(self, result):
return {'data': ectd.convert(result)}
#api.add_resource(ectdtext, '/ectd/<result>')
categories=convert('/home/brian/ajay/files/5ca21af9-5b67-45f8-969c-ae571431c665.pdf')
#app.route('/')
def returnResult():
return categories
#app.route('/', defaults={'path': ''})
#app.route('/<path:path>')
def get_dir(path):
return path
##app.route('/get_dir/<path>')
#def get_dir(path):
# return path
if __name__ == '__main__':
app.run(host="0.0.0.0", port=5000)

Related

flask_apispec library makes Flask app to crash when use_kwargs decorator is used

I am building a Restful API in Python 3.8 using flask_restful, flask_apispec, and marshmallow. When I enable use_kwargs decorator my app is crushing on a POST with TypeError: post() takes 1 positional argument but 2 were given
I'd appreciate any help in solving this bug.
# requirements.txt
aniso8601==9.0.1
apispec==5.1.1
certifi==2021.10.8
charset-normalizer==2.0.7
click==8.0.3
Flask==2.0.2
flask-apispec==0.11.0
Flask-RESTful==0.3.9
gunicorn==20.1.0
idna==3.3
itsdangerous==2.0.1
Jinja2==3.0.2
MarkupSafe==2.0.1
marshmallow==3.14.0
pytz==2021.3
requests==2.26.0
six==1.16.0
tableauserverclient==0.17.0
urllib3==1.26.7
webargs==8.0.1
Werkzeug==2.0.2
from apispec import APISpec
from flask import Flask, request
from flask_restful import Resource, Api
from apispec.ext.marshmallow import MarshmallowPlugin
from flask_apispec.extension import FlaskApiSpec
from marshmallow import Schema, fields, post_load, ValidationError
from flask_apispec.views import MethodResource
from flask_apispec import use_kwargs, marshal_with
app = Flask(__name__) # Flask app instance initiated
api = Api(app) # Flask restful wraps Flask app around it.
app.config.update({
'APISPEC_SPEC': APISpec(
title='Kube Controller',
version='v1',
plugins=[MarshmallowPlugin()],
openapi_version='2.0.0'
),
'APISPEC_SWAGGER_URL': '/swagger/', # URI to access API Doc JSON
'APISPEC_SWAGGER_UI_URL': '/swagger-ui/' # URI to access UI of API Doc
})
docs = FlaskApiSpec(app)
class AwesomeRequestSchema(Schema):
api_type = fields.String(required=True)
#post_load
def create(self, data, **kwargs):
return MyAPI(**data)
class MyAPI:
def __init__(self, api_type):
self.api_type = api_type
self.message = "hi"
class AwesomeAPI(MethodResource, Resource):
#use_kwargs(AwesomeRequestSchema)
#marshal_with(AwesomeRequestSchema, code=200, description='Something created')
def post(self):
"""
POST
"""
try:
schema = AwesomeRequestSchema()
data = schema.load(request.json)
print(data.api_type)
return request.json
except ValidationError as err:
return err.messages
api.add_resource(AwesomeAPI, '/')
docs.register(AwesomeAPI)
if __name__ == '__main__':
app.run(debug=True)
Thanks!
I had the same issue. The use_kwargs decorator will try to populate and inject the AwesomeRequestSchema object into the post() method: https://flask-apispec.readthedocs.io/en/latest/api_reference.html#flask_apispec.annotations.use_kwargs
To fix, replace
def post(self):
with
def post(self, populated_request_object):

How to return 401 in flask despite authorization

I am new to flask and I want to return 401 error, I am not using authentication, I am simply using a parameter api_key to check whether the user is authenticated.
I've tried abort(401) and return false, but it returns error 400 'Bad Request', is this the default way it returns a 401. Or is there a different way to do this?
My Code:
import flask
from flask import jsonify, request, Response
from flask_cors import CORS, cross_origin
from GoogleNews import GoogleNews
googlenews = GoogleNews()
googlenews.set_lang('en')
googlenews.set_period('1d')
googlenews.set_encode('utf-8')
app=flask.Flask(__name__)
cors = CORS(app)
app.config['CORS_HEADERS'] = 'Content-Type'
#cross_origin()
#app.route('/', methods=["GET"])
def return_news():
API_KEY = request.args['api_key']
if API_KEY == "xyz":
googlenews.get_news('TECHNOLOGY')
return jsonify(googlenews.result(True)[0:4])
else:
return Response(response="Unauthorized", status=401)
Thankyou
instead, try flask.Response object.
from flask import Flask, Response
app = Flask(__name__)
#app.route("/abort")
def abort():
return Response(response="Unauthorized", status=401)
app.run()
without the actual code it is hard to tell, but I think it is not using the flask abort() but the python internal abort() function.
Check the code below:
import flask
app = flask.Flask("aborter")
#app.route("/abort")
def abort():
return flask.abort(401)
if __name__ == '__main__':
app.run()
Happy Coding

Google Drive API Webhook

I have set up a google drive webhook through the "watch property"(https://developers.google.com/drive/api/v2/reference/files/watch) and it is working well and submitting a response as soon as any changes are detected on the watch file. However, the request body (i.e.posted_data=request.get_data( )) as below comes back empty (i.e. None). I have tried other options such as request.json but still empty. Does anyone have any ideas on what I am possibly doing wrong? My Python Flask webhook code is below and works well (i.e. any file updates are posted) except that it returns an empty data type (i.e.posted_data=request.get_data( ) is None). Any suggestions are highly appreciated!
from datetime import datetime
from flask import Flask, request, jsonify
import pytz
def get_timestamp():
dt=datetime.now(pytz.timezone('US/Central'))
return dt.strftime(("%Y-%m-%d %H:%M:%S"))
app = Flask(__name__)
#app.route('/webhook', methods=['POST','GET'])
def webhook():
if request.method=='GET':
return '<h1> This is a webhook listener!</h1>'
if request.method == 'POST':
posted_data=request.get_data( )
print("We have received a request =====>",posted_data)
cur_date=get_timestamp()
print("Date and time of update ====>",cur_date)
http_status=jsonify({'status':'success'}),200
else:
http_status='',400
return http_status
if __name__ == '__main__':
app.run(port=5000)
The above code works except that google will post their response as headers (i.e. request.headers). See updated code below.
from datetime import datetime
from flask import Flask, request, jsonify
import pytz
def get_timestamp():
dt=datetime.now(pytz.timezone('US/Central'))
return dt.strftime(("%Y-%m-%d %H:%M:%S"))
app = Flask(__name__)
#app.route('/webhook', methods=['POST','GET'])
def webhook():
if request.method=='GET':
return '<h1> This is a webhook listener!</h1>'
if request.method == 'POST':
print(request.headers)
cur_date=get_timestamp()
print("Date and time of update ====>",cur_date)
http_status=jsonify({'status':'success'}),200
else:
http_status='',400
return http_status
if __name__ == '__main__':
app.run(port=5000)

Unable to decode "devanagari text" passed as URL param

My Python Flask App is unable to decode the devanagari text eg:"सिंगापूर" that I pass as urlparam from my postman. If I sen english text it handles it well.
My PostMan query :
GET http://localhost:5000/getSimilarWord/सिंगापूर
from flask import Flask
from flask_restful import Resource, Api
class DevnagriText(Resource):
def get(self, textInput):
print("parsed String is :",textInput)
return {'text': textInput}
api.add_resource(DevnagriText, '/getWord/<string:textInput>')
if __name__ == '__main__':
app.run(debug=True)
The output I get on console is
{
"text": "\u00818"
}
Instead of
{
"text": "सिंगापूर"
}
You need to prevent the response from forcing ASCII: app.config['JSON_AS_ASCII'] = False
So in your example:
from flask import jsonify, Flask
from flask_restful import Resource, Api
app = Flask(__name__)
app.config['JSON_AS_ASCII'] = False
api = Api(app)
class DevnagriText(Resource):
def get(self, textInput):
print("parsed String is :",textInput)
return jsonify(text=textInput)
api.add_resource(DevnagriText, '/getWord/<string:textInput>')
if __name__ == '__main__':
app.run(debug=True)
But, this doesn't really matter, it will all get interpreted the same way if it gets read into Python or JavaScript.

Python - no attribute 'as_view' Error

I am trying to write a new python rest api like below,
from flask import Flask
from com.app.Controller import Event1LogicClass
from com.app.Controller import Event2LogicClass
from flask import Flask
from flask_restful import Api
com.app:
app = Flask(__name__)
apiRest = Api(app)
apiRest.add_resource(Event1LogicClass, '/Count/<string:days>')
apiRest.add_resource(Event2LogicClass,'/Count/<string:days>/<string:givenDate>')
if __name__ == '__main__':
app.run(debug = True)
com.app.Controller :
class Event1LogicClass(Resource)
def get(self, days):
return "Event1LogicClass"
com.app.Controller :
class Event2LogicClass(Resource)
def get(self, days, givenDate):
return "Event2LogicClass"
When I select MainClass as main class and run then It gives
resource_func = self.output(resource.as_view(endpoint, *resource_class_args,
AttributeError: module 'com.app.Controller.Event1LogicClass' has no attribute 'as_view'
I want to add multiple rest call in MainClass and call the api functionality depending on class in apiRest.add_resource.
where am I doing wrong?

Resources