summaryrefslogtreecommitdiff
path: root/opendc-web/opendc-web-api/app.py
diff options
context:
space:
mode:
authorFabian Mastenbroek <mail.fabianm@gmail.com>2021-10-25 14:53:54 +0200
committerFabian Mastenbroek <mail.fabianm@gmail.com>2021-10-25 14:53:54 +0200
commitaa9b32f8cd1467e9718959f400f6777e5d71737d (patch)
treeb88bbede15108c6855d7f94ded4c7054df186a72 /opendc-web/opendc-web-api/app.py
parenteb0e0a3bc557c05a70eead388797ab850ea87366 (diff)
parentb7a71e5b4aa77b41ef41deec2ace42b67a5a13a7 (diff)
merge: Integrate v2.1 progress into public repository
This pull request integrates the changes planned for the v2.1 release of OpenDC into the public Github repository in order to sync the progress of both repositories.
Diffstat (limited to 'opendc-web/opendc-web-api/app.py')
-rwxr-xr-xopendc-web/opendc-web-api/app.py137
1 files changed, 137 insertions, 0 deletions
diff --git a/opendc-web/opendc-web-api/app.py b/opendc-web/opendc-web-api/app.py
new file mode 100755
index 00000000..36c80b7a
--- /dev/null
+++ b/opendc-web/opendc-web-api/app.py
@@ -0,0 +1,137 @@
+#!/usr/bin/env python3
+import mimetypes
+import os
+
+from dotenv import load_dotenv
+from flask import Flask, jsonify, redirect
+from flask_compress import Compress
+from flask_cors import CORS
+from flask_restful import Api
+from flask_swagger_ui import get_swaggerui_blueprint
+from marshmallow import ValidationError
+
+from opendc.api.jobs import JobList, Job
+from opendc.api.portfolios import Portfolio, PortfolioScenarios
+from opendc.api.prefabs import Prefab, PrefabList
+from opendc.api.projects import ProjectList, Project, ProjectTopologies, ProjectPortfolios
+from opendc.api.scenarios import Scenario
+from opendc.api.schedulers import SchedulerList
+from opendc.api.topologies import Topology
+from opendc.api.traces import TraceList, Trace
+from opendc.auth import AuthError
+from opendc.util import JSONEncoder
+
+
+# Load environmental variables from dotenv file
+load_dotenv()
+
+
+def setup_sentry():
+ """
+ Setup the Sentry integration for Flask if a DSN is supplied via the environmental variables.
+ """
+ if 'SENTRY_DSN' not in os.environ:
+ return
+
+ import sentry_sdk
+ from sentry_sdk.integrations.flask import FlaskIntegration
+
+ sentry_sdk.init(
+ integrations=[FlaskIntegration()],
+ traces_sample_rate=0.1
+ )
+
+
+def setup_api(app):
+ """
+ Setup the API interface.
+ """
+ api = Api(app)
+ # Map to ('string', 'ObjectId') passing type and format
+ api.add_resource(ProjectList, '/projects/')
+ api.add_resource(Project, '/projects/<string:project_id>')
+ api.add_resource(ProjectTopologies, '/projects/<string:project_id>/topologies')
+ api.add_resource(ProjectPortfolios, '/projects/<string:project_id>/portfolios')
+ api.add_resource(Topology, '/topologies/<string:topology_id>')
+ api.add_resource(PrefabList, '/prefabs/')
+ api.add_resource(Prefab, '/prefabs/<string:prefab_id>')
+ api.add_resource(Portfolio, '/portfolios/<string:portfolio_id>')
+ api.add_resource(PortfolioScenarios, '/portfolios/<string:portfolio_id>/scenarios')
+ api.add_resource(Scenario, '/scenarios/<string:scenario_id>')
+ api.add_resource(TraceList, '/traces/')
+ api.add_resource(Trace, '/traces/<string:trace_id>')
+ api.add_resource(SchedulerList, '/schedulers/')
+ api.add_resource(JobList, '/jobs/')
+ api.add_resource(Job, '/jobs/<string:job_id>')
+
+ @app.errorhandler(AuthError)
+ def handle_auth_error(ex):
+ response = jsonify(ex.error)
+ response.status_code = ex.status_code
+ return response
+
+ @app.errorhandler(ValidationError)
+ def handle_validation_error(ex):
+ return {'message': 'Input validation failed', 'errors': ex.messages}, 400
+
+ return api
+
+
+def setup_swagger(app):
+ """
+ Setup Swagger UI
+ """
+ SWAGGER_URL = '/docs'
+ API_URL = '../schema.yml'
+
+ swaggerui_blueprint = get_swaggerui_blueprint(
+ SWAGGER_URL,
+ API_URL,
+ config={
+ 'app_name': "OpenDC API v2"
+ },
+ oauth_config={
+ 'clientId': os.environ.get("AUTH0_DOCS_CLIENT_ID", ""),
+ 'additionalQueryStringParams': {'audience': os.environ.get("AUTH0_AUDIENCE", "https://api.opendc.org/v2/")},
+ }
+ )
+ app.register_blueprint(swaggerui_blueprint)
+
+
+def create_app(testing=False):
+ app = Flask(__name__, static_url_path='/')
+ app.config['TESTING'] = testing
+ app.config['SECRET_KEY'] = os.environ['OPENDC_FLASK_SECRET']
+ app.config['RESTFUL_JSON'] = {'cls': JSONEncoder}
+ app.json_encoder = JSONEncoder
+
+ # Define YAML content type
+ mimetypes.add_type('text/yaml', '.yml')
+
+ # Setup Sentry if DSN is specified
+ setup_sentry()
+
+ # Set up CORS support
+ CORS(app)
+
+ # Setup compression
+ compress = Compress()
+ compress.init_app(app)
+
+ setup_api(app)
+ setup_swagger(app)
+
+ @app.route('/')
+ def index():
+ """
+ Redirect the user to the API documentation if it accesses the API root.
+ """
+ return redirect('docs/')
+
+ return app
+
+
+application = create_app(testing="OPENDC_FLASK_TESTING" in os.environ)
+
+if __name__ == '__main__':
+ application.run()