Skip to content

Commit

Permalink
Merge pull request #20 from ScilifelabDataCentre/allow_CORS
Browse files Browse the repository at this point in the history
Setting up some minor protection placeholders for backend API
  • Loading branch information
SevLG authored Apr 18, 2024
2 parents 97fd43f + 3d75af8 commit af7991a
Show file tree
Hide file tree
Showing 6 changed files with 54 additions and 1 deletion.
8 changes: 8 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
__pycache__/
.github/
.venv/
.env
.envExample
.gitignore
LICENSE
README.md
6 changes: 6 additions & 0 deletions .envExample
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# example showing which variables are set in .env or a kubernetes ConfigMap
# needs to be set for apps to run correctly
FRONTEND_URL = ""
# The request header from the frontend will contain an 'X-api-key' which
# must match with this key to allow API operations
API_KEY = ""
5 changes: 5 additions & 0 deletions app.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,20 @@
import os
from dotenv import load_dotenv

from flask import Flask
from flask_smorest import Api
from flask_migrate import Migrate
from flask_cors import CORS

from db import db

from resources.articles import blp as ArticleBlueprint

def create_app(db_url=None):
load_dotenv(override=True)

app = Flask(__name__)
CORS(app, origins=[os.getenv("FRONTEND_URL")])

app.config["PROPAGATE_EXCEPTIONS"] = True
app.config["API_TITLE"] = "Precision Medicine Portal REST API"
Expand Down
3 changes: 2 additions & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ flask-smorest
python-dotenv
sqlalchemy
flask-sqlalchemy
flask-migrate
flask-migrate
flask_cors
6 changes: 6 additions & 0 deletions resources/articles.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,24 +7,28 @@
from schemas import ArticleGetSchema, PlainArticleSchema, ArticleUpdateSchema

from utils import generate_url_from_title
from security import api_key_required


blp = Blueprint("Articles", __name__, description="Operations on articles")

@blp.route("/article/<string:article_id>")
class Article(MethodView):
@api_key_required
@blp.response(200, ArticleGetSchema)
def get(self, article_id):
# from flask sql-alchemy, automatically aborts if not found
article = ArticleModel.query.get_or_404(article_id)
return article

@api_key_required
def delete(self, article_id):
article = ArticleModel.query.get_or_404(article_id)
db.session.delete(article)
db.session.commit()
return {"message": "Article deleted."}

@api_key_required
@blp.arguments(ArticleUpdateSchema)
@blp.response(200, ArticleGetSchema)
def put(self, article_data, article_id):
Expand All @@ -47,10 +51,12 @@ def put(self, article_data, article_id):

@blp.route("/article")
class ArticleList(MethodView):
@api_key_required
@blp.response(200, ArticleGetSchema(many=True))
def get(self):
return ArticleModel.query.all()

@api_key_required
@blp.arguments(PlainArticleSchema)
@blp.response(201, ArticleGetSchema)
def post(self, article_data):
Expand Down
27 changes: 27 additions & 0 deletions security.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import os

import functools
from flask import request
from flask_smorest import abort

def is_valid(api_key):
return os.getenv("API_KEY") == api_key

def api_key_required(func):
@functools.wraps(func)
def decorator(*args, **kwargs):
api_key = request.headers.get("x-api-key")
if not api_key:
abort(
400,
message="Please provide an API key."
)
# Check if API key is correct and valid
if is_valid(api_key):
return func(*args, **kwargs)
else:
abort(
403,
message="The provided API key is not valid."
)
return decorator

0 comments on commit af7991a

Please sign in to comment.