session object in Fastapi similar to flask - python

I am trying to use session to pass variables across view functions in fastapi. However, I do not find any doc which specifically says of about session object. Everywhere I see, cookies are used. Is there any way to convert the below flask code in fastapi? I want to keep session implementation as simple as possible.
from flask import Flask, session, render_template, request, redirect, url_for
app=Flask(__name__)
app.secret_key='asdsdfsdfs13sdf_df%&'
#app.route('/a')
def a():
session['my_var'] = '1234'
return redirect(url_for('b'))
#app.route('/b')
def b():
my_var = session.get('my_var', None)
return my_var
if __name__=='__main__':
app.run(host='0.0.0.0', port=5000, debug = True)

Take a look at Starlette's SessionMiddleware. FastAPI uses Starlette under the hood so it is compatible.
After you register SessionMiddleware, you can access Request.session, which is a dictionary.
Documentation: SessionMiddleware
An implementation in FastAPI may look like:
#app.route("/a")
async def a(request: Request) -> RedirectResponse:
request.session["my_var"] = "1234"
return RedirectResponse("/b")
#app.route("/b")
async def b(request: Request) -> PlainTextResponse:
my_var = request.session.get("my_var", None)
return PlainTextResponse(my_var)

Related

FastAPI/Starlette's SessionMiddleware creates new session for every request

I need to create a session for authentication in the session_set endpoint. However, for some reason, the session is still being created in the session_info endpoint. How to make a session created only in session_set? Otherwise, I have a new session in the response with each request.
Here is my code:
import uvicorn
from fastapi import FastAPI, Request
from starlette.middleware.sessions import SessionMiddleware
app = FastAPI()
app.add_middleware(SessionMiddleware, secret_key="some-random-string", max_age=None)
#app.get("/a")
async def session_set(request: Request):
request.session["my_var"] = "1234"
return 'ok'
#app.get("/b")
async def session_info(request: Request):
my_var = request.session.get("my_var", None)
return my_var
if __name__ == '__main__':
uvicorn.run('http-session:app', port=5000, reload=True)
You could use a Middleware to override the session value in the Response cookies (check the documentation in Starlette as well) every time a new request arrives; hence, the session will remain the same.
Note: Remember to declare your custom middleware, after adding the SessionMiddleware to the app instance, as the order that endpoints/sub-applications are defined in your application matters, as described in this answer (see the relevant FastAPI documentation as well).
Working Example:
from fastapi import FastAPI, Request
from starlette.middleware.sessions import SessionMiddleware
app = FastAPI()
app.add_middleware(SessionMiddleware, secret_key="some-random-string")
#app.middleware("http")
async def some_middleware(request: Request, call_next):
response = await call_next(request)
session = request.cookies.get('session')
if session:
response.set_cookie(key='session', value=request.cookies.get('session'), httponly=True)
return response
#app.get("/a")
def func_a(request: Request):
request.session["my_var"] = "1234"
print(request.cookies.get('session'))
return 'OK'
#app.get("/b")
def func_b(request: Request):
my_var = request.session.get("my_var", None)
print(request.cookies.get('session'))
return my_var

How do I mimic Java Springs #PathVariable using Python Flask

from flask import Flask, jsonify, request
from flask_restful import Api, Resource
app = Flask(__name__)
api = Api(app)
user_dict = {}
class User(Resource):
def __init__(self):
user_id = 0
def get(self):
return jsonify(user_dict[id])
api.add_resource(User, "/user")
if __name__ == "__main__":
app.run(debug=True)
The idea is that when a GET request is made to /user/1, then the get method returns that key/value pair of the user_dict. How do I do path variables in Python? Please assume that the dictionary is not empty.
Flask uses <variable_name> or <converter:variable_name> placeholders in URL path registrations.
This is used in the examples shown in the Flask-Restful Quickstart documentation:
class TodoSimple(Resource):
def get(self, todo_id):
return {todo_id: todos[todo_id]}
def put(self, todo_id):
todos[todo_id] = request.form['data']
return {todo_id: todos[todo_id]}
api.add_resource(TodoSimple, '/<string:todo_id>')
Here <string:todo_id> is a path variable, passed to the TodoSimple.get() and TodoSimple.put() methods as an argument.
Flask-Restful otherwise assumes a general familiarity with Flask's patterns, I strongly recommend you read through at least the Flask Quickstart document, and I recommend you also work through the tutorial, if nothing else.
For your specific example, if user ids are always integers, use:
class User(Resource):
def get(self, user_id):
return jsonify(user_dict[user_id])
api.add_resource(User, "/user/<int:user_id>")

how do I make get request directly to a flask app object

I inherited a project that uses flask. This flask application has several APIs, each API has a GET function that returns a json object.
I was asked to implement an additional API that requests information from the other APIs. So my question is how do I make a GET request directly to a flask application? Is it something like....
from flask import request
#app.route('/root_dir/api_number_1/info', methods=['GET'])
def request_info_from_api_number_1():
return request.get_json()
#app.route('/root_dir/api_number_2/info', methods=['GET'])
def request_info_from_api_number_2():
return request.get_json()
When I do this the functions return None. I suppose I could always make an http request to the flask url and specify the address as localhost but it seems strange to have to make an http request when I can directly access the flask app object.
Could you just use the existing api functions?
from flask import Flask
app = Flask(__name__)
#app.route("/foo")
def foo():
return "foo"
#app.route("/foobar")
def foobar():
return foo() + "bar"
if __name__ == "__main__":
app.run(debug=True)

Flask: Set session variable from URL Param

I have a website that needs to be rebranded depending on the URL that a visitor comes in on. For the most part, the content is the same but the CSS is different. I'm brand new to flask and relatively new to session cookies, but I think the best way to do this is to create a session cookie containing a "client" session variable. Then, depending on the client (brand), I can append a specific css wrapper to a template.
How can I access URL params and set one of the param values to a session variable? For example, if a visitor comes in on www.example.com/index?client=brand1, then I'd like to set session['client'] = brand1.
My app.py file:
import os
import json
from flask import Flask, session, request, render_template
app = Flask(__name__)
# Generate a secret random key for the session
app.secret_key = os.urandom(24)
#app.route('/')
def index():
session['client'] =
return render_template('index.html')
#app.route('/edc')
def edc():
return render_template('pages/edc.html')
#app.route('/success')
def success():
return render_template('success.html')
#app.route('/contact')
def contact():
return render_template('pages/contact.html')
#app.route('/privacy')
def privacy():
return render_template('pages/privacy.html')
#app.route('/license')
def license():
return render_template('pages/license.html')
#app.route('/install')
def install():
return render_template('pages/install.html')
#app.route('/uninstall')
def uninstall():
return render_template('pages/uninstall.html')
if __name__ == '__main__':
app.run(debug=True)
You could do so in a #flask.before_request decorated function:
#app.before_request
def set_client_session():
if 'client' in request.args:
session['client'] = request.args['client']
set_client_session will be called on each incoming request.

Flask Pluggable Views Error: "Not Implemented Error"

I am learning how to use Pluggable Views in Flask, since it seems that everyone uses them always for their advantages. I have the following file which returns an "Not Implemented Error". I am assuming that is because I am not implementing the dispatch_request. However, according to Flask's documentation, when using MethodView: "...if you implement a method called get() it means you will response to ’GET’ requests and the dispatch_request() implementation will automatically forward your request to that." Meaning, I do not require dispatch_request.
from flask import Flask, render_template, request, redirect, url_for, flash
from flask.views import View, MethodView
import os
SECRET_KEY = 'some_secret_key'
DEBUG = TRUE
app = Flask(__name__)
app.config.from_object(__name__)
class Main(View):
def dispatch_request(self):
return "Hello World!"
class Template(View):
def get(self):
return render_template('index.html')
def post(self):
result = eval(request.form['expression'])
flash(result)
return self.get()
app.add_url_rule('/', view_func=Main.as_view('main'))
app.add_url_rule('/template', view_func=Template.as_view('template'), methods=['GET', 'POST'])
if __name__ == "__main__":
app.run()
Oops.. silly Python beginner's mistake by me.
I was subclassing flask.views.View instead of flask.views.MethodView. flask.views.View requires dispatch_request, and does not automatically forward HTTP requests to dispatch_request as MethdoView does, hence the error.

Categories

Resources