Multiple Clients¶
Sometime, projects requires multiple api that require different configuration, such as different middleware for authentication or discovery mechanism.
The pyramid-blacksmith plugin enabled that by name your client factory.
the default name is client
, but it can be override using the
blacksmith.clients
setting.
This settings is a list such as
blacksmith.clients =
client_foo
client_bar
In that case, the request.blacksmith
property will contains to functions,
name client_foo
and client_bar
but there is no client
.
Example¶
ini file¶
###
# app configuration
# http://docs.pylonsproject.org/projects/pyramid/en/latest/narr/environment.html
###
[app:main]
use = egg:notif
pyramid.includes =
pyramid_blacksmith
blacksmith.scan =
notif.resources
blacksmith.clients =
client_static
client_consul
client_router
blacksmith.client_static.service_discovery = static
blacksmith.client_static.static_sd_config =
user/v1 http://user:8000/v1
blacksmith.client_static.error_parser = notif:MyError
blacksmith.client_consul.service_discovery = consul
blacksmith.client_consul.consul_sd_config =
addr http://consul:8500/v1
service_name_fmt {service}-{version}
service_url_fmt http://{address}:{port}/{version}
unversioned_service_name_fmt {service}
unversioned_service_url_fmt http://{address}:{port}
blacksmith.client_consul.error_parser = notif:MyError
blacksmith.client_router.service_discovery = router
blacksmith.client_router.router_sd_config =
service_url_fmt http://router/{service}-{version}/{version}
unversioned_service_url_fmt http://router/{service}
blacksmith.client_router.error_parser = notif:MyError
###
# wsgi server configuration
###
[server:main]
use = egg:waitress#main
host = 0.0.0.0
port = 8000
###
# Pserve configuration
###
[pserve]
watch_files =
*
%(here)s/notif/**/*.py
/home/notif/.cache/pypoetry/virtualenvs/**/*.py
###
# logging configuration
# http://docs.pylonsproject.org/projects/pyramid/en/latest/narr/logging.html
###
[loggers]
keys = root, notif
[handlers]
keys = console
[formatters]
keys = generic
[logger_root]
level = INFO
handlers = console
[logger_notif]
level = DEBUG
handlers =
qualname = notif
[handler_console]
class = StreamHandler
args = (sys.stderr,)
level = NOTSET
formatter = generic
[formatter_generic]
format = %(asctime)s %(levelname)-5.5s [%(name)s][%(threadName)s] %(message)s
pyramid views¶
import email as emaillib
import smtplib
from textwrap import dedent
from blacksmith import SyncConsulDiscovery
from pyramid.config import Configurator
from notif.resources.user import User
smtp_sd = SyncConsulDiscovery()
def send_email(user: User, message: str):
email_content = dedent(
f"""\
Subject: notification
From: notification@localhost
To: "{user.firstname} {user.lastname}" <{user.email}>
{message}
"""
)
msg = emaillib.message_from_string(email_content)
srv = smtp_sd.resolve("smtp", None)
# XXX Synchronous socket here, OK for the example
# real code should use aiosmtplib
s = smtplib.SMTP(srv.address, int(srv.port))
s.send_message(msg)
s.quit()
def post_notif_using_static(request):
if request.method == "GET":
return {"detail": "Use POST to test the static driver"}
body = request.json
api_user = request.blacksmith.client_static("api_user")
user: User = (api_user.users.get({"username": body["username"]})).unwrap()
send_email(user, body["message"])
return {"detail": f"{user.email} accepted"}
def post_notif_using_consul(request):
if request.method == "GET":
return {"detail": "Use POST to test the consul driver"}
body = request.json
api_user = request.blacksmith.client_consul("api_user")
user: User = (api_user.users.get({"username": body["username"]})).unwrap()
send_email(user, body["message"])
return {"detail": f"{user.email} accepted"}
def post_notif_using_router(request):
if request.method == "GET":
return {"detail": "Use POST to test the router driver"}
body = request.json
api_user = request.blacksmith.client_router("api_user")
user: User = (api_user.users.get({"username": body["username"]})).unwrap()
send_email(user, body["message"])
return {"detail": f"{user.email} accepted"}
def main(global_config, **settings):
"""Build the pyramid WSGI App."""
with Configurator(settings=settings) as config:
config.add_route("notify_v1", "/v1/notification")
config.add_view(
post_notif_using_static, route_name="notify_v1", renderer="json"
)
config.add_route("notify_v2", "/v2/notification")
config.add_view(
post_notif_using_consul, route_name="notify_v2", renderer="json"
)
config.add_route("notify_v3", "/v3/notification")
config.add_view(
post_notif_using_router, route_name="notify_v3", renderer="json"
)
app = config.make_wsgi_app()
return app