Retrieving config from a blueprint in Sanic app
Question:
I have a Sanic application, and want to retrieve app.config
from a blueprint as it holds MONGO_URL
, and I will pass it to a repository class from the blueprint.
However, I could not find how to get app.config
in a blueprint. I have also checked Flask solutions, but they are not applicable to Sanic.
My app.py
:
from sanic import Sanic
from routes.authentication import auth_route
from routes.user import user_route
app = Sanic(__name__)
app.blueprint(auth_route, url_prefix="/auth")
app.blueprint(user_route, url_prefix="/user")
app.config.from_envvar('TWEETBOX_CONFIG')
app.run(host='127.0.0.1', port=8000, debug=True)
My auth blueprint
:
import jwt
from sanic import Blueprint
from sanic.response import json, redirect
from domain.user import User
from repository.user_repository import UserRepository
...
auth_route = Blueprint('authentication')
mongo_url = ?????
user_repository = UserRepository(mongo_url)
...
@auth_route.route('/signin')
async def redirect_user(request):
...
Answers:
There is a variable named current_app in Flask. You can use current_app.config["MONGO_URL"]
.
But I am not familiar with Sanic.
I think you can create a config.py to save your configuration, just like
config.py
config = {
'MONGO_URL':'127.0.0.1:27017'
}
and use it in app.py
from config import config
mongo_url = config['MONGO_URL']
I would suggest a slightly different approach, based on the 12 Factor App (very interesting read which, among others, provides a nice guideline on how to protect and isolate your sensitive info).
The general idea is to place your sensitive and configuration variables in a file that is going to be gitignored and therefore will only be available locally.
I will try to present the method I tend to use in order to be as close as possible to the 12 Factor guidelines:
-
Create a .env
file with your project variables in it:
MONGO_URL=http://no_peeking_this_is_secret:port/
SENSITIVE_PASSWORD=for_your_eyes_only
CONFIG_OPTION_1=config_this
DEBUG=True
...
-
(Important) Add .env
and .env.*
on your .gitignore
file, thus protecting your sensitive info from been uploaded to GitHub.
-
Create an env.example
(be careful not to name it with a .
in the beginning, because it will get ignored).
In that file, you can put an example of the expected configuration in order to be reproducible by simply copy, paste, rename to .env
.
-
In a file named settings.py
, use decouple.config
to read your config file into variables:
from decouple import config
MONGO_URL = config('MONGO_URL')
CONFIG_OPTION_1 = config('CONFIG_OPTION_1', default='')
DEBUG = config('DEBUG', cast=bool, default=True)
...
-
Now you can use these variables wherever is necessary for your implementation:
myblueprint.py
:
import settings
...
auth_route = Blueprint('authentication')
mongo_url = settings.MONGO_URL
user_repository = UserRepository(mongo_url)
...
As a finisher, I would like to point out that this method is framework (and even language) agnostic so you can use it on Sanic
as well as Flask
and everywhere you need it!
The Sanic way…
Inside a view method, you can access the app
instance from the request
object. And, therefore access your configuration.
@auth_route.route('/signin')
async def redirect_user(request):
configuration = request.app.config
2021-10-10 Update
There are two newer ways to get to the configuration values (or, perhaps more accuratlely getting the application instance from which you can get the configuration). The first version might be more on point to answering the question of how to get to the config from the blueprint. However, the second option is probably the preferred method since it is precisely intended for this kind of use.
Alternative #1
Blueprints have access to the Sanic applications they are attached to beginning with v21.3.
Therefore, if you have a blueprint object, you can trace that back to the application instance, and therefore also the config value.
app = Sanic("MyApp")
bp = Blueprint("MyBlueprint")
app.blueprint(bp)
assert bp.apps[0] is app
The Blueprint.apps
property is a set
because it is possible to attach a single blueprint to multiple applications.
Alternative #2
Sanic has a built-in method for retrieving an application instance from the global scope beginning in v20.12. This means that once an application has been instantiated, you can retrieve it using: Sanic.get_app()
.
app = Sanic("MyApp")
assert Sanic.get_app() is app
This method will only work if there is a single Sanic
instance available. If you have multiple application instances, you will need to use the optional name
argument:
app1 = Sanic("MyApp")
app2 = Sanic("MyOtherApp")
assert Sanic.get_app("MyApp") is app1
I have a Sanic application, and want to retrieve app.config
from a blueprint as it holds MONGO_URL
, and I will pass it to a repository class from the blueprint.
However, I could not find how to get app.config
in a blueprint. I have also checked Flask solutions, but they are not applicable to Sanic.
My app.py
:
from sanic import Sanic
from routes.authentication import auth_route
from routes.user import user_route
app = Sanic(__name__)
app.blueprint(auth_route, url_prefix="/auth")
app.blueprint(user_route, url_prefix="/user")
app.config.from_envvar('TWEETBOX_CONFIG')
app.run(host='127.0.0.1', port=8000, debug=True)
My auth blueprint
:
import jwt
from sanic import Blueprint
from sanic.response import json, redirect
from domain.user import User
from repository.user_repository import UserRepository
...
auth_route = Blueprint('authentication')
mongo_url = ?????
user_repository = UserRepository(mongo_url)
...
@auth_route.route('/signin')
async def redirect_user(request):
...
There is a variable named current_app in Flask. You can use current_app.config["MONGO_URL"]
.
But I am not familiar with Sanic.
I think you can create a config.py to save your configuration, just like
config.py
config = {
'MONGO_URL':'127.0.0.1:27017'
}
and use it in app.py
from config import config
mongo_url = config['MONGO_URL']
I would suggest a slightly different approach, based on the 12 Factor App (very interesting read which, among others, provides a nice guideline on how to protect and isolate your sensitive info).
The general idea is to place your sensitive and configuration variables in a file that is going to be gitignored and therefore will only be available locally.
I will try to present the method I tend to use in order to be as close as possible to the 12 Factor guidelines:
-
Create a
.env
file with your project variables in it:MONGO_URL=http://no_peeking_this_is_secret:port/ SENSITIVE_PASSWORD=for_your_eyes_only CONFIG_OPTION_1=config_this DEBUG=True ...
-
(Important) Add
.env
and.env.*
on your.gitignore
file, thus protecting your sensitive info from been uploaded to GitHub. -
Create an
env.example
(be careful not to name it with a.
in the beginning, because it will get ignored).
In that file, you can put an example of the expected configuration in order to be reproducible by simplycopy, paste, rename to .env
. -
In a file named
settings.py
, usedecouple.config
to read your config file into variables:from decouple import config MONGO_URL = config('MONGO_URL') CONFIG_OPTION_1 = config('CONFIG_OPTION_1', default='') DEBUG = config('DEBUG', cast=bool, default=True) ...
-
Now you can use these variables wherever is necessary for your implementation:
myblueprint.py
:import settings ... auth_route = Blueprint('authentication') mongo_url = settings.MONGO_URL user_repository = UserRepository(mongo_url) ...
As a finisher, I would like to point out that this method is framework (and even language) agnostic so you can use it on Sanic
as well as Flask
and everywhere you need it!
The Sanic way…
Inside a view method, you can access the app
instance from the request
object. And, therefore access your configuration.
@auth_route.route('/signin')
async def redirect_user(request):
configuration = request.app.config
2021-10-10 Update
There are two newer ways to get to the configuration values (or, perhaps more accuratlely getting the application instance from which you can get the configuration). The first version might be more on point to answering the question of how to get to the config from the blueprint. However, the second option is probably the preferred method since it is precisely intended for this kind of use.
Alternative #1
Blueprints have access to the Sanic applications they are attached to beginning with v21.3.
Therefore, if you have a blueprint object, you can trace that back to the application instance, and therefore also the config value.
app = Sanic("MyApp")
bp = Blueprint("MyBlueprint")
app.blueprint(bp)
assert bp.apps[0] is app
The Blueprint.apps
property is a set
because it is possible to attach a single blueprint to multiple applications.
Alternative #2
Sanic has a built-in method for retrieving an application instance from the global scope beginning in v20.12. This means that once an application has been instantiated, you can retrieve it using: Sanic.get_app()
.
app = Sanic("MyApp")
assert Sanic.get_app() is app
This method will only work if there is a single Sanic
instance available. If you have multiple application instances, you will need to use the optional name
argument:
app1 = Sanic("MyApp")
app2 = Sanic("MyOtherApp")
assert Sanic.get_app("MyApp") is app1