Adding service which provides a simple news feed (#2)
* Adding service which provides a simple news feed
* Added inital README
* Renaming const to express what it does
* Removed LICENSE
New file |
| | |
| | | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. |
| | | |
| | | # IDEs |
| | | .idea |
| | | |
| | | # dependencies |
| | | /venv |
| | | __pycache__ |
| | | |
| | | # misc |
| | | .DS_Store |
New file |
| | |
| | | FROM ubi8/python-36 |
| | | |
| | | ENV FLASK_APP="gossip.py" |
| | | |
| | | COPY src /app |
| | | COPY requirements.txt /app |
| | | |
| | | WORKDIR /app |
| | | |
| | | RUN pip install -r requirements.txt |
| | | |
| | | EXPOSE 5000 |
| | | |
| | | CMD [ "flask", "run", "--host=0.0.0.0"] |
New file |
| | |
| | | # Gossip Service |
| | | |
| | | The Gossip Service is a small application written in [Python](https://www.python.org/) + [Flask](https://flask.palletsprojects.com) |
| | | which exposes a variable endpoint in order to retrieve news from a specific topic. It Comes with CORS enabled so it can |
| | | be used from browsers. |
| | | |
| | | ## How it works |
| | | |
| | | The application exposes a `GET` endpoint `/news/<topic>` on port `5000` by default. Once a GET request hits the service, |
| | | the application uses the `<topic>` part of the endpoint to find a json file with that name. |
| | | |
| | | In the case of not being able to locate a file with the `<topic>` name, the application throws a 404 error. In any other |
| | | case, the application loads the list of news from the json file, picks 3 randomly and returns the list sorted by their |
| | | timestamp. |
| | | |
| | | Template of the json used to store the news: |
| | | ```json |
| | | { |
| | | "data": [ |
| | | { |
| | | "anyFieldKey": "anyFieldValue", |
| | | "timestamp": 1578454302 |
| | | } |
| | | ] |
| | | } |
| | | ``` |
| | | |
| | | The only requirements for the json files are: |
| | | - Be a well formed JSON file |
| | | - The `data` field should exists and stores the list of news objects |
| | | - Each news element should have a `timestamp` field |
| | | |
| | | ## Installation |
| | | |
| | | The Gossip Service is a Python application with Flask so, in order to run in your local machine you need Python + some |
| | | libraries. |
| | | |
| | | A simple approach is to have different Python virtual environments per project. Execute the following command in the |
| | | root of this project ot install a virtual environment: |
| | | |
| | | ``` |
| | | $ python3 -m virtualenv venv |
| | | ``` |
| | | |
| | | Once the virtual environment is installed in the project, you need to activate this new virtual environment. Execute the |
| | | following command to activate it: |
| | | |
| | | ``` |
| | | . venv/bin/activate |
| | | ``` |
| | | |
| | | After the activation of the virtual environment you need to install all the requirements for the service (unless you did |
| | | this step before). Execute the following command to install all the required libraries: |
| | | |
| | | ``` |
| | | pip install -r requirements.txt |
| | | ``` |
| | | |
| | | ## Running Gossip in local |
| | | |
| | | To run the Gossip Service in local, execute the following commands: |
| | | |
| | | ``` |
| | | $ cd src |
| | | $ export FLASK_APP=gossip.py |
| | | $ flask run |
| | | ``` |
| | | |
| | | ## Running Gossip in a containers environment |
| | | |
| | | In order to run the Gossip Service in a containers environment you need a container image. A prebuilt image is |
| | | available in [quay.io](https://quay.io/repository/psolarvi/python-flask-gossip) |
| | | |
New file |
| | |
| | | Flask |
| | | flask-cors |
New file |
| | |
| | | { |
| | | "data": [ |
| | | { |
| | | "id": "8f9f00d0-acce-4eda-9b31-2251ab393846", |
| | | "title": "Energy Sector +0.20%", |
| | | "timestamp": 1578454302 |
| | | }, |
| | | { |
| | | "id": "26fabd5b-d21e-405e-a624-e03a21b8d5ef", |
| | | "title": "Financials Sector -0.77%", |
| | | "timestamp": 1579263010 |
| | | }, |
| | | { |
| | | "id": "451bf2da-9af4-417b-bc5f-bb14bcdbdfc8", |
| | | "title": "Basic Materials Sector -0.48%", |
| | | "timestamp": 1579724882 |
| | | }, |
| | | { |
| | | "id": "a20e3370-52df-4631-8028-b1ba2ede2257", |
| | | "title": "Healthcare Sector +0.92%", |
| | | "timestamp": 1580165061 |
| | | }, |
| | | { |
| | | "id": "c8b770ed-997d-45ba-89a2-d10e9951e0d2", |
| | | "title": "Industrials Sector -1.02%", |
| | | "timestamp": 1580240625 |
| | | }, |
| | | { |
| | | "id": "35b7d3a9-0e47-40ab-aeed-b223ad6a8afa", |
| | | "title": "Technology Sector +0.11%", |
| | | "timestamp": 1581686667 |
| | | }, |
| | | { |
| | | "id": "e3ffea9c-5025-4d48-a451-e78cbbb37f79", |
| | | "title": "Cyclical Goods & Services Sector +0.07%", |
| | | "timestamp": 1581921237 |
| | | }, |
| | | { |
| | | "id": "52048c22-d270-4224-9f01-dc70d32c4fb1", |
| | | "title": "Non-Cyclical Goods & Services Sector +0.33%", |
| | | "timestamp": 1582278201 |
| | | }, |
| | | { |
| | | "id": "b7fc7f33-b777-4ec2-89ef-2339cbf662b5", |
| | | "title": "Utilities Sector +0.46%", |
| | | "timestamp": 1583351796 |
| | | } |
| | | ] |
| | | } |
New file |
| | |
| | | import json |
| | | import random |
| | | from flask import abort, Flask, jsonify |
| | | from flask_cors import CORS |
| | | from markupsafe import escape |
| | | |
| | | app = Flask(__name__) |
| | | CORS(app) |
| | | |
| | | NUM_OF_NEWS = 3 |
| | | |
| | | def sortByTimestamp(element): |
| | | return element['timestamp'] |
| | | |
| | | @app.errorhandler(404) |
| | | def topicNotFound(error): |
| | | return "Unable to find the specific topic", 404 |
| | | |
| | | @app.route('/news/<string:topic>') |
| | | def getNewsForTopic(topic): |
| | | try: |
| | | # Loading the file which has the topic news |
| | | with open('./data/%s.json' % escape(topic)) as topicFile: |
| | | news = json.load(topicFile) |
| | | |
| | | # Picking only a few elements from the list of news |
| | | randomSelection = random.sample(news['data'], NUM_OF_NEWS) |
| | | |
| | | # Sorting the resulting list by the timestamp |
| | | randomSelection.sort(key=sortByTimestamp) |
| | | |
| | | return jsonify(randomSelection) |
| | | |
| | | # If we can not find a file for the topic, we throw a 404 error |
| | | except IOError: |
| | | abort(404) |