How to configure basepath in flask restful api application? - python

I want to set a basepath for my flask application. I have mentioned one example below.
basepath = 'http://localhost:3000/api'
i have two api call one is GET and other one is POST .
from flask import Flask
from flask_restful import Api
app = Flask(__name__)
api = Api(app)
api.add_resource(CreateUser, "/v1/user/create/")
api.add_resource(CreateUser, "/v1/user/details")
class CreateUser(Resource):
def post(self):
# Code for creating a user
def get(self):
# Code for get the details of user.
So here, if i want to create the user then my url will be http://localhost:3000/api/v1/user/create/
so same for GET also . So how do i achieve this ?

Initialize your Api with the path prefix:
from flask import Flask
from flask_restful import Api
app = Flask(__name__)
api = Api(app, "/api")
...
You can't change the host and port this way, you'll have to run flask with parameters:
flask run --host=127.0.0.1 --port=3000
Or you could do
from flask import Flask
from flask_restful import Resource, Api
app = Flask(__name__)
api = Api(app, "/api")
...
if __name__ == "__main__":
app.run(host="127.0.0.1", port="3000")
Please keep in mind this is not intended for production environments, only for local testing. Please see https://flask.palletsprojects.com/en/1.1.x/tutorial/deploy/ for using in a production environment.
If you want to get those values from basepath, one option would be purl:
url = purl.URL('http://localhost:3000/api')
url.host() # --> "localhost"
url.port() # --> 3000
url.path() # --> "/api"

Related

Flask 404 error when initializing a connection with a react applicaiont

import os, re
from flask import Flask, send_from_directory, json,request
from flask_socketio import SocketIO
from flask_cors import CORS
from flask_sqlalchemy import SQLAlchemy
import random
app = Flask(__name__, static_folder='./build/static')
# Point SQLAlchemy to your Heroku database
uri = os.getenv("DATABASE_URL") # or other relevant config var
if uri and uri.startswith("postgres://"):
uri = uri.replace("postgres://", "postgresql://", 1)
app.config['SQLALCHEMY_DATABASE_URI'] = uri
# Gets rid of a warning
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db = SQLAlchemy(app)
import models
cors = CORS(app, resources={r"/*": {"origins": "*"}})
socketio = SocketIO(
app,
cors_allowed_origins="*",
json=json,
manage_session=False
)
#app.route('/', defaults={"filename": "index.html"})
#app.route('/<path:filename>')
def index(filename):
return send_from_directory('./build', filename)
# When a client connects from this Socket connection, this function is run
#socketio.on('connect')
def on_connect():
print('User connected!')
# When a client disconnects from this Socket connection, this function is run
#socketio.on('disconnect')
def on_disconnect():
print('User disconnected!')
#socketio.on('index')
def on_index():
all_students = db.Students.query.all()
random1 = random.randint(0,models.Students.query().count())
random2 = random.randint(0,models.Students.query().count())
total_table = []
for student in all_students:
total_table.append(student)
firstStudent = []
secondStudent = []
while(random2 == random1):
random2 = random.randint(0,models.Students.query().count())
firstStudent.append(total_table[random1])
secondStudent.append(total_table[random2])
twoStudents = [firstStudent,secondStudent]
socketio.emit('students', {twoStudents:twoStudents})
# Note we need to add this line so we can import app in the python shell
if __name__ == "__main__":
# Note that we don't call app.run anymore. We call socketio.run with app arg
socketio.run(
app,
)
The react end of the application launches fine with no errors, and the database has no issues. I've used this skeleton for the base of a bunch of other projects and i've never had any issues. But for some reason i'm stuck at a brick wall setting this up. I know the issue is within the #app.route('/') part of the code. i've tried hard coding the html file into the url path, but that just causes other errors like missing 1 required positional argument: 'filename' flask. Any help is greatly appreciated
I tested your configuration and it doesn't give me any errors. Nevertheless I offer you an alternative solution.
You can provide the entire react build folder as a static folder. You can then deliver the "index.html" as a single file in the root route. The prerequisite is that the prefix for the static url path is empty.
# ...
app = Flask(__name__,
static_url_path='',
static_folder='./build'
)
# ...
#app.route('/')
def index():
return app.send_static_file('index.html')
# ...

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.

CORS request did not succeed in python flask-socketio

I need help in debugging -the Same Origin Policy disallows reading the remote resource at https://some-domain.com. (Reason: CORS request did not succeed) in python flask-socketio error.
I am working on a chat application using python flask-socketio. In previously I have created that application in local and it works fine as expected, while I move the below code to the server it shows the above error. The client code runs in the https servers and server code also runs on the https server I don't know why that error shows.
I have attached my code below and please give a better solution to me.
server.py
import json
import os
from flask import Flask, render_template, request,session
from flask_socketio import SocketIO, send, emit
from datetime import timedelta,datetime
from flask_cors import CORS
app = Flask(__name__)
app.config['SECRET_KEY'] = 'secretkey'
app.config['DEBUG'] = True
app.config['CORS_HEADERS'] = 'Content-Type'
cors = CORS(app, resources={r"/*": {"origins": "*"}})
socketio = SocketIO(app)
users = {}
#app.before_request
def make_session_permanent():
session.permanent = True
app.permanent_session_lifetime = timedelta(minutes=1)
#app.route('/')
##cross_origin(origin='*',headers=['Content- Type','Authorization'])
def index():
return render_template('index.html')
#socketio.on('connect')
def connect():
print("connected");
#app.route('/orginate')
def orginate():
socketio.emit('server orginated', 'Something happened on the server!')
return '<h1>Sent!</h1>'
#socketio.on('username')
def receive_username(username):
users[username] = request.sid
#users.append({username : request.sid})
#print(users)
emit('userList', users, broadcast=True)
print('Username added!')
print(users)
if _name_ == '__main__':
socketio.run(app,host='xxx.xxx.xx.x',port=5001)
client.js
var socket = io.connect("https://xxx.xxx.xx.x:5001/",{secure:false});
Screenshot 1:
This screenshot explains the access-control-allow-orgin works fine for images under static folder in flask framework
Screenshot 2:
This screenshot explains there is no access-control-orgin for socket call
You are using Flask-CORS to set up CORS on your Flask routes. You are missing a similar set up for Flask-SocketIO:
socketio = SocketIO(app, cors_allowed_origins=your_origins_here)
You can use '*' as the value to allow all origins (which I do not recommend), or set a single origin as a string, or a list of origins as a list of strings.

Difficulty implementing server side session storage using redis and flask

I have a setup where a node.js app is making ajax requests to a flask based python server. Since ajax requests lack cookie data, I can't use the simple flask session object to persist data across requests. To remedy this, I'd like to implement a redis based server side implementation of a session storage system, but the solutions I've found so far do not work.
One solution I've tried is the following this snippet.
But this doesn't work. Is there more setup I need to do to configure redis beyond what is mentioned in the quickstart guide? Here is my attempt:
...
from flask import session
# Snippet code is copy pasted here verbatum
import session_interface
...
app = Flask(__name__)
app.session_interface = session_interface.RedisSessionInterface()
...
# Can't access this as session['key'] across requests
session['key'] = value
...
if __name__ == '__main__':
app.secret_key = '123456789012345678901234'
app.run(debug=True)
Another solution I've tried is importing the Flask-Session extention.
However, I can't get this to work either. The section I'm confused about is the following:
"We are not supplying something like SESSION_REDIS_HOST and SESSION_REDIS_PORT, if you want to use the RedisSessionInterface, you should configure SESSION_REDIS to your own redis.Redis instance. This gives you more flexibility, like maybe you want to use the same redis.Redis instance for cache purpose too, then you do not need to keep two redis.Redis instance in the same process."
What is meant by this section and how would I have figured this out? Here is my attempt to make this extension work:
...
from flask import session
from flask_session import Session
import redis
...
app = Flask(__name__)
SESSION_TYPE = 'redis'
app.config.from_object(__name__)
Session(app)
...
# Can't access this as session['key'] across requests
session['key'] = value
...
if __name__ == '__main__':
app.secret_key = '123456789012345678901234'
app.run(debug=True)
Has anyone successfully implemented manual session storage on a server running flask? Are there other options for getting this functionality?
Thanks for your input.
I think that's because you missed the URL configuration for your storage Redis, to check that, you can use Redis-CLI to see if there is anything being inserted into Redis.
I use this code and it worked:
from flask import Flask
from flask_session import Session
import redis
……
app = Flask(__name__)
app.config['SESSION_TYPE'] = 'redis'
app.config['SESSION_REDIS'] = redis.from_url('127.0.0.1:6379')
sess = Session()
sess.init_app(app)
def getSession():
return session.get('key', 'not set')
def setSession():
session.set('key')=123
return 'ok'
……
The following works for me:
...
from flask_session import Session
import redis
...
app = Flask(__name__)
SECRET_KEY = '123456789012345678901234'
SESSION_TYPE = 'redis'
SESSION_REDIS = redis.from_url('localhost:6379')
app.config.from_object(__name__)
sess = Session()
sess.init_app(app)
...
# Should be available accross requests now
session['key'] = value
...
if __name__ == '__main__':
app.run(debug=True)
Using sess.init_app(app) instead of Session(app) did the trick.

Flask doesn't locate template directory when running with twisted

Following some advice that I found here I am trying to use Flask as a web interface for an application that runs with twisted.
As suggested in Flask documentation I created a "templates" directory which is at the same level as my script but when I launch the server I get the following error:
Internal Server Error
The server encountered an internal error and was unable to complete your request. Either the server is overloaded or there is an error in the application.
When I do not try to load a template and just write a string in the request it works fine. This is what makes me think it is related to the load of the template.
from twisted.internet import reactor
from twisted.web.resource import Resource
from twisted.web.wsgi import WSGIResource
from twisted.internet.threads import deferToThread
from twisted.web.server import Site, NOT_DONE_YET
from flask import Flask, request, session, redirect, url_for, abort, \
render_template, flash
app= Flask(__name__)
app.config.from_object(__name__)
#app.route('/login', methods= ['GET', 'POST'])
def login():
return render_template('login.html', error= error)
if __name__ == '__main__':
root = WSGIResource(reactor, reactor.getThreadPool(), app)
factory = Site(root)
reactor.listenTCP(8880, factory)
reactor.run()
Some frameworks will change directory from your current working directory when they are run in daemon mode, and this might very well be the case here.
Flask, since 0.7, has supported passing a template_folder keyword argument when calling Flask, so you could try:
import os
tmpl_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'templates')
The following is a shorter version that will work just fine:
tmpl_dir = os.path.join(os.path.dirname(__file__), 'templates)
# ...
app = Flask('myapp', template_folder=tmpl_dir)
You can feed Jinja2 with a default templates directory (as written here) like this :
import jinja2
app = Flask(__name__)
app.jinja_loader = jinja2.FileSystemLoader('path/to/templates/directory')

Categories