How to use Python 3 imports properly in Google Cloud Functions - python

I am making a simple function to check a URL status and redirect on 404. This app works fine in Flask localhost but when I move this to Google Cloud Functions, I keep getting "Error: could not handle the request". This is when my parameters on both the Cloud Function and the localhost are the exact same.
Am I doing something wrong with importing 'redirect' from Flask?
GCLOUD CODE: NOT WORKING
from flask import Flask, redirect
from flask import request
import requests
def urlincoming():
custID = request.args['custID']
token = request.args['token']
custEmail = request.args['custEmail']
storeDomain = request.args['domain']
adminEmail = request.args['adminEmail']
baseUrl = f"{storeDomain}/account/reset/{custID}/{token}"
baseUrlFailedAuth = f"{storeDomain}/account/invalid_token"
requestBaseUrl = requests.head(baseUrl)
if(requestBaseUrl.status_code == 200):
return redirect(baseUrl)
else:
return redirect(baseUrlFailedAuth)
LOCALHOST CODE: WORKING
from flask import Flask, redirect
from flask import request
import requests
app = Flask(__name__)
#app.route('/urlincoming')
def urlincoming():
custID = request.args['custID']
token = request.args['token']
custEmail = request.args['custEmail']
storeDomain = request.args['domain']
adminEmail = request.args['adminEmail']
baseUrl = f"{storeDomain}/account/reset/{custID}/{token}"
baseUrlFailedAuth = f"{storeDomain}/account/invalid_token"
requestBaseUrl = requests.head(baseUrl)
if(requestBaseUrl.status_code == 200):
return redirect(baseUrl)
else:
return redirect(baseUrlFailedAuth)

All Google Cloud Functions need to have one of the following two signatures:
HTTP Functions:
function_name(request):
...
Background functions:
function_name(data, context):
...
Depending on the type of function you're creating, you either need to add the request or data, context arguments.

from flask import redirect
import requests
def urlincoming(request):
I was able to fix things by adding the request as a argument but I'm not sure why it worked :/

Related

Use secret key to secure flask API - python

Is it possible to use a secret key to secure just an API without a website or webpage?
I made an app that uses flask and when I test it from the client app, it works. However I want to secure the get request from the client to the server by using a secret key or token if possible.
The problem is that most examples I have seen assumed you are using this for a website with login credentials. I don't have any webpages or any routes in my flask app.
Here is the server side:
from flask import Flask, stream_with_context, request, Response
from flask_restful import Api, Resource
from flask_socketio import SocketIO
import intermedia_choose_action_flask
import subprocess
from io import StringIO
import sys
import sqlite_companysearch
import time
app = Flask(__name__)
api = Api(app)
SECRET_KEY = "a long set of strings I got from running a command in linux terminal"
app.secret_key = SECRET_KEY
class addspamblacklistspecific(Resource):
def get(self, emailordomain):
count = 0
sqlite_companysearch.comp_searchall_intermedia()
selection_cid = sqlite_companysearch.comp_searchall_intermedia.cid_selection_results
for cid in selection_cid:
subprocess.Popen(["python3", "/home/tech/scripts/Intermedia_automate/intermedia_choose_action.py", "--addblockspecific", "--cp", cid, "--ed", emailordomain], bufsize=10, errors='replace')
count = count + 1
if count == 3:
time.sleep(60)
count = 0
return "command completed succesfully"
api.add_resource(addspamblacklistspecific, "/addspamblacklistspecific/<string:emailordomain>")
if __name__ == "__main__":
app.run(debug=True)
Here is the client side:
from flask import json
import requests
#where do I put in a secret key?
def email_or_domain_selection():
email_or_domain_selection.email_select = input("""Enter an email or domain.
(NOTE: domains must have a "*" symbol infront of the name. For example *company.com)
Enter Email or Domain :""")
eselect = email_or_domain_selection.email_select
return email_or_domain_selection.email_select
email_or_domain_selection()
BASE = "http://127.0.0.1:5000/"
response = requests.get(BASE + "addspamblacklistspecific/"+email_or_domain_selection.email_select)
print(response.text)
I figure I should learn this before learning how to put my app in the cloud.
Thank you for your time,
Edit - I was told to read this: demystify Flask app.secret_key which I already did. That is for if you have webpages. I don't have any webpages and am just trying to secure an API only. It doesn't explain how or if I should be using session information for just calling an api from a client side. It doesn't explain how to use a secret key on the client side.
You could look into flask-httpauth. I used this a while back on one of my projects to add a layer of security to some API's running on flask. Keep in mind that this is only a basic authentication (base-64 encoded strings).
from flask import Flask, jsonify, request
from flask_restful import Resource, Api
from flask_httpauth import HTTPBasicAuth
# import credentials from env (suggested)
API_UNAME = "username"
API_PASS = "password"
USER_DATA = {API_UNAME: API_PASS}
# initialize flask/flask-restful instance
app = Flask(__name__)
api = Api(app)
auth = HTTPBasicAuth()
class API_Class(Resource):
#auth.login_required
def post(self):
# do api stuff
return jsonify("result")
# verify API authentication
#auth.verify_password
def verify(username, password):
if not (username and password):
return False
return USER_DATA.get(username) == password
api.add_resource(API_Class, "/post")
You might want to look into other methods like OAuth for extra security.

Issue with simple python API in flask. Trying to create a post method to add json data to a list

I am trying to build a simple flask api to post json data to a list (eventually with be redshift but this is just a simple test program).
I have attached the api code first followed by the code to send data.
I am getting internal server error issues when running the second script.
The code seems very simple though and I cannot figure out what is wrong.
from flask_restful import Api, Resource
from flask import request
app = Flask(__name__)
api = Api(app)
audit_log = []
class audit(Resource):
#def get (self):
#return {"data":"HelloWorld"}
def put (self):
new_item = request.get_json()
audit_log.append(new_item)
return new_item
api.add_resource(audit,"/")
app.run()
import requests
BASE = "HTTP://127.0.0.1:5000/"
response = requests.put(BASE, params = {'auditid' : 'xyz', 'jobname' : 'abc'})
print (response.json())
It seems that you haven't imported the Flask properly
instead of this
from flask import request
use this
from flask import Flask, request
This should work fine...

How can i get url parameters in python?

I have tried a lot of things but nothing is working. It always gives me the "Incomplete response received from application" message in the navigator.
My code is:
import sys
from flask import Flask, request
app = Flask(__name__)
#app.route('/')
def application():
uri = request.args.get('url')
message = 'It works!\n'
response = '\n'.join([message, uri])
return response
The problem is or in the #app.route('/') line or in the uri = request.args.get('url').
I just want to call the with the navigator like http://example.com/script/?url=hello.
I tried changing #app.route('/') to #app.route('/script') and #app.route('/script/') but nothing is working... any ideas?
Thanks a lot!
For future readers: note that the original question has been edited in response to this suggestion.
First issue: You seem to be using some very low-level WSGI implementation when Flask does a lot of the sugar for you. Consider testing with a function that lets Flask do the work and then expand as needed.
import sys
from flask import Flask, request
app = Flask(__name__)
#app.route('/')
def test():
uri = request.args.get('url')
message = 'It works!\n'
version = 'Python %s\n' % sys.version.split()[0]
response = '\n'.join([message, version, uri])
return response
Next, keep in mind that Flask wants a string return type. If you want to pass a data structure back, consider jsonify.

Flask-pymongo RuntimeError: Working outside of application context

I'm writing a program to read mongodb document based on id field using flask-pymongo. But I'm getting error, can anybody tell me where am I going wrong?
code:
from flask import Flask, make_response, jsonify
from flask_pymongo import PyMongo
from collections import OrderedDict
from bson import json_util
import json
app = Flask('__name__')
app.config['MONGO_DBNAME'] = 'db_name'
app.config['MONGO_URI'] = 'mongodb://192.168.55.24:27017/db_name'
mongo_connection = PyMongo(app)
#app.route('/')
def index(inp_id):
collection = mongo_connection.db.table_name
one_record = collection.find_one({'id': inp_id})
obj_str = json_util.dumps(one_record)
obj_dict = json.loads(obj_str, object_hook=OrderedDict)
return make_response(jsonify(obj_dict), 200)
if __name__ == '__main__':
index('5cd00a468b36db516b6d2f16') # I think this is where I'm going wrong
giving me the below error:
RuntimeError: Working outside of application context.
If I pass id value directly in the place of inp_id I get the result but I'm trying to write a generic one.
Flask has an application context, You might need to use app.app_context() to make it work.
The application context keeps track of the application-level data
during a request, CLI command, or other activity. Rather than passing
the application around to each function, the current_app and g proxies
are accessed instead.
Try this :
def index(inp_id):
with app.app_context():
collection = mongo_connection.db.table_name
one_record = collection.find_one({'id': inp_id})
obj_str = json_util.dumps(one_record)
obj_dict = json.loads(obj_str, object_hook=OrderedDict)
return make_response(jsonify(obj_dict), 200)
For more information, read Flask Application context

flask context inside context , for jsonfy, all in a single page

I'm having a single test for retrieve documents in a single page, i know it's not correct to do in a single page; but it's just to understand all this work like pure script, not for an api restful.
My problem is when i use:
print (jsonify({'result' : output}))
i've get this 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.
when I replace this line by
print ( output)
have no erros and have the documents.
How i can to specify a context for jsonify ? inside another context ? because i'm already using
with app.app_context():
Here the code:
from flask import Flask
from flask import g
from flask import jsonify
from flask import request
from flask_pymongo import PyMongo
from flask import make_response
from bson.objectid import ObjectId
from flask import current_app
import sys
app = Flask(__name__)
app.config['MONGO_DBNAME'] = 'restdb'
app.config['MONGO_URI'] = 'mongodb://localhost:27017/crm1'
#app.errorhandler(404)
def not_found(error):
return make_response(jsonify({'error':'Notfound' }),404)
with app.app_context():
mongo = PyMongo(app)
star = mongo.db.accounts
output = []
for s in star.find():
output.append({'id': str(s['_id']) ,'firstname' : s['firstname'], 'lastname' : s['lastname']})
print (jsonify({'result' : output}))
#print ( output)
if __name__ == '__main__':
app.run(debug=True)
Jsonify Works with HttpResponse.
You can use python json module and print the output
Like:
import json
print(json.dumps(output))

Categories