diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000000000000000000000000000000000000..942e4c259e0279970ca708f14307e424a9b27843 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,13 @@ +__pycache__/ +*.pyc +*.pyo +*.pyd +*.pyc +.dockerignore +Dockerfile +*.log +*.sqlite +*.json +*.csv +appsettings.json +tv_shows.csv \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index 97f58cf45acfb1035da50f8f74466058c7f3e477..4157200f8b0e51b026104d8ebf9e02c0c42318a8 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,12 +1,13 @@ -# syntax=docker/dockerfile:1 - FROM python:3.9-slim-buster - -WORKDIR /flask-docker +WORKDIR /app +EXPOSE 80 +EXPOSE 5000 +EXPOSE 8080 +EXPOSE 443 COPY requirements.txt requirements.txt -RUN pip3 install -r requirements.txt +RUN pip install --no-cache-dir -r requirements.txt COPY . . -CMD [ "python", "app.py"] +CMD ["gunicorn", "-w", "4", "app:app_with_args", "-b", "0.0.0.0:5000"] \ No newline at end of file diff --git a/app.py b/app.py index 73c14836f42fe371203270678fa8ad4c5c9311d5..35f2d0e8f9f0e7acf37033af09609de41be76207 100644 --- a/app.py +++ b/app.py @@ -3,7 +3,7 @@ import os import re import pandas as pd -from flask import Flask, jsonify, request +from flask import Flask, jsonify from flask_cors import CORS from flask_restx import Api, Resource, fields from pymongo import MongoClient, errors @@ -18,7 +18,10 @@ app.config.from_object(__name__) # enable CORS CORS(app) # enable flask_restx -api = Api(app) +api = Api(app, version='1.0', title='TV Series Microservice', + description='This microservice returns recommendations and a list of shows', + default="TV Series", default_label="The TV Series namespace") +api.documentation_path = "/swagger.json" def _get_value_for_keys(keys, obj, default): @@ -95,12 +98,19 @@ series_recommendations_model = api.model('SeriesRecommendations', { 'recommendations': fields.List(fields.Nested(series_info_model)) }) +series_paged_model = api.model('SeriesPaged', { + 'page': fields.Integer, + 'shows': fields.List(fields.Nested(series_info_model)), + 'total_pages': fields.Integer, + 'total_shows': fields.Integer +}) + def initialise_db(): try: # check if appsettings.json exists if os.path.isfile('appsettings.json'): - uri = pd.read_json('appsettings.json')['ConnectionStrings'].values[0] + uri = pd.read_json('appsettings.json')['ConnectionString'].values[0] # check if connection string is empty if uri: pass @@ -276,9 +286,10 @@ class SeriesInfoById(Resource): @api.route('/api/tv_shows/<int:page>') @api.doc(responses={200: 'application/json'}) class TvShows(Resource): + @api.marshal_with(series_paged_model) def get(self, page): # Get the page number from the request arguments, defaulting to 1 if not provided - #page = int(request.args.get('page', 1)) + # page = int(request.args.get('page', 1)) # Define the number of shows to display per page shows_per_page = 20 @@ -319,14 +330,24 @@ class TvShows(Resource): 'shows': response_data } - return jsonify(response) + return response -if __name__ == '__main__': +def create_app(): global collection collection = initialise_db() - # requires connection to MongoDB collection in order for Flask to run - if collection != None: - app.run(host='0.0.0.0', port=5000, debug=False) - else: + if collection is None: print('Flask server not run as a connection to the MongoDB collection could not be established.') + exit(1) + + return app + + +def app_with_args(environ, start_response): + create_app() + return app(environ, start_response) + + +if __name__ == '__main__': + create_app() + app.run(host='0.0.0.0', port=5000, debug=False) diff --git a/requirements.txt b/requirements.txt index d3834d3ef02b6c36ad0d80aff7fab1cc52b1fd75..1d4d07130e2bde9843e58d8dc22037393487156e 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,9 +1,8 @@ -# Automatically generated by https://github.com/damnever/pigar. - -Flask==2.1.2 +Flask==2.2.2 Flask-Cors==3.0.10 flask-restx==1.1.0 -pandas==1.4.2 +pandas==2.0.1 pymongo==4.3.3 scikit-learn==1.1.2 spacy==3.4.3 +gunicorn==20.1.0 \ No newline at end of file