SkyPortal Extensions#
It is common for specific instances of SkyPortal to employ “extensions”, which use added components and APIs not available in the baseline app, usually because of particular forms of data access and distribution. Some examples include Fritz or SkyPortal-GRANDMA.
For the APIs, they will have a folder: extensions/skyportal/skyportal/handlers/api For redux, they will have a folder: extensions/skyportal/static/js/ducks For the components, they will have a folder: extensions/skyportal/static/js/components
When deploying, files are copied into each of these SkyPortal folders from your repository.
For APIs in particular, a dedicated app_server.py
needs to be created. To deploy, it will take a form similar to this, where in addition to the baseline application loaded with
from skyportal.app_server import make_app
Custom handlers are added as follows (taking Fritz as an example):
from skyportal.handlers.api.alert import (
AlertHandler,
AlertAuxHandler,
AlertCutoutHandler,
AlertTripletsHandler,
)
from skyportal.handlers.api.archive import (
ArchiveCatalogsHandler,
ArchiveHandler,
CrossMatchHandler,
)
from skyportal.handlers.api.kowalski_filter import KowalskiFilterHandler
from skyportal.handlers.api.tns_info import TNSInfoHandler
fritz_handlers = [
# Fritz-specific API endpoints
# Alerts
(r"/api/alerts(/.+)?", AlertHandler),
(r"/api/alerts_aux(/.+)?", AlertAuxHandler),
(r"/api/alerts_cutouts(/.+)?", AlertCutoutHandler),
(r"/api/alerts_triplets(/.+)?", AlertTripletsHandler),
# Archive
(r"/api/archive", ArchiveHandler),
(r"/api/archive/catalogs", ArchiveCatalogsHandler),
(r"/api/archive/cross_match", CrossMatchHandler),
# Alert Stream filter versioning via K:
(r"/api/filters/([0-9]+)?/v", KowalskiFilterHandler),
(r"/api/tns_info/(.*)", TNSInfoHandler),
]
and then those handlers are added to the baseline app:
app = make_app(cfg, baselayer_handlers, baselayer_settings, process, env)
app.add_handlers(r".*", fritz_handlers) # match any host
This is known as the “app factory”, which is a function used to create the Tornado application. This is often needed to add additional routes, or do certain setup procedures before the application is run.
To add accessible routes to the web interface, one configures the config.yaml as follows.
routes:
- path: "/alerts"
component: Alerts
- path: "/alerts/ztf/:id"
component: ZTFAlert
- path: "/archive"
component: Archive
where each path in the browser is tied to a specific React.js component as rendered.
For certain Javascript components we also have “Plugins”, through which functionality can be added to extend those pages. These are currently available on the Source (SourcePlugins.jsx
), Candidates (CandidatePlugins.jsx
), Filters (FilterPlugins.jsx
), and About (AboutPlugins.jsx
) pages.
Settings for extensions can be specified in the config.yaml
. Taking fritz as an example again, here is a segment that configures kowalski
:
kowalski:
protocol: https
host: kowalski.caltech.edu
port: 443
token: YOUR_TOKEN_HERE
Your extension can read the configuration as follows:
from baselayer.app.env import load_env
env, cfg = load_env()
and then access specific entries with calls like:
protocol = cfg["app.kowalski.protocol"]