From 5e10342e5ea4e469910ae7a9cc9faa560bf6282f Mon Sep 17 00:00:00 2001 From: Ahimbisibwe Roland Date: Sat, 18 Aug 2018 15:43:16 +0300 Subject: [PATCH 01/10] [Feature:#159868126] Add endpoint for question answers --- api/app/controllers/AnswersController.py | 9 ++++++++ api/app/controllers/__init__.py | 3 ++- api/app/models/Answer.py | 5 +++++ api/app/models/Question.py | 4 +++- api/app/routes.py | 3 ++- api/core/error_handler.py | 3 ++- api/core/storage/relationships.py | 1 + api/core/storage/storage.py | 3 ++- tests/feature/test_QuestionAnswers.py | 26 ++++++++++++++++++++++++ 9 files changed, 52 insertions(+), 5 deletions(-) create mode 100644 api/app/controllers/AnswersController.py create mode 100644 api/app/models/Answer.py create mode 100644 tests/feature/test_QuestionAnswers.py diff --git a/api/app/controllers/AnswersController.py b/api/app/controllers/AnswersController.py new file mode 100644 index 0000000..23130e6 --- /dev/null +++ b/api/app/controllers/AnswersController.py @@ -0,0 +1,9 @@ +from flask import jsonify +from api.app.models import Question + + +class AnswersController: + @classmethod + def index(cls, question_id): + question = Question.find_or_fail(question_id).load("answers") + return jsonify(dict(data=question["answers"])) diff --git a/api/app/controllers/__init__.py b/api/app/controllers/__init__.py index f8ab0eb..202397c 100644 --- a/api/app/controllers/__init__.py +++ b/api/app/controllers/__init__.py @@ -1,5 +1,6 @@ from .HomeController import HomeController from .QuestionsController import QuestionsController +from .AnswersController import AnswersController -__all__ = ["HomeController", "QuestionsController"] +__all__ = ["HomeController", "QuestionsController", "AnswersController"] diff --git a/api/app/models/Answer.py b/api/app/models/Answer.py new file mode 100644 index 0000000..be8ff66 --- /dev/null +++ b/api/app/models/Answer.py @@ -0,0 +1,5 @@ +from api.core.storage import Model + + +class Answer(Model): + pass diff --git a/api/app/models/Question.py b/api/app/models/Question.py index 3449f8a..d2a3bff 100644 --- a/api/app/models/Question.py +++ b/api/app/models/Question.py @@ -1,5 +1,7 @@ from api.core.storage import Model +from .Answer import Answer class Question(Model): - pass + def answers(self): + return self.has_many(Answer) diff --git a/api/app/routes.py b/api/app/routes.py index b87b703..cb32f92 100644 --- a/api/app/routes.py +++ b/api/app/routes.py @@ -4,5 +4,6 @@ Router.group([ Router.get("/", HomeController, "index"), - Router.resource("/questions", QuestionsController) + Router.resource("/questions", QuestionsController), + Router.resource("/questions.answers", AnswersController) ]).prefix("/api/v1.0") diff --git a/api/core/error_handler.py b/api/core/error_handler.py index c141e4d..7d499d1 100644 --- a/api/core/error_handler.py +++ b/api/core/error_handler.py @@ -6,7 +6,8 @@ def validation_exception(e): def not_found_exception(e): - return jsonify(e.response), 404 + response = e.response or dict(error="Resource doesn't exist") + return jsonify(response), 404 def handle_errors(app): diff --git a/api/core/storage/relationships.py b/api/core/storage/relationships.py index d9ec09b..5cc19fb 100644 --- a/api/core/storage/relationships.py +++ b/api/core/storage/relationships.py @@ -32,6 +32,7 @@ def children(self): def load(self): self.parent[self.child_key] = self._load_data() + return self.parent class HasMany(Relationship): diff --git a/api/core/storage/storage.py b/api/core/storage/storage.py index c63d532..d848c91 100644 --- a/api/core/storage/storage.py +++ b/api/core/storage/storage.py @@ -154,6 +154,7 @@ def has_many(self, child, parent_id="id", child_id=None): def load(self, *args): for key in args: self._load_relation_ship(key) + return self def _load_relation_ship(self, key): relationship = getattr(self, key)() @@ -191,7 +192,7 @@ def or_where(cls, *args, **kwargs): @classmethod def hydrate(cls, models): - return list(map(cls, models)) + return [cls(model) for model in models] def to_json(self): diff --git a/tests/feature/test_QuestionAnswers.py b/tests/feature/test_QuestionAnswers.py new file mode 100644 index 0000000..b044bf1 --- /dev/null +++ b/tests/feature/test_QuestionAnswers.py @@ -0,0 +1,26 @@ +from tests.feature import BaseTestCase + + +class TestQuestionAnswers(BaseTestCase): + def setUp(self): + super().setUp() + + self.question = dict( + title="Travis CI", + description="How do I integrate Travis" + ) + self.add_question() + + def add_question(self): + rv = self.post("/questions", self.question) + self.api_question = rv.get_json()["data"] + + def answers_url(self, id=""): + return f"/questions/{self.api_question['id']}/answers" + + def answer_url(self, id): + return f"{self.answers_url()}/{id}" + + def test_it_fetches_a_list_of_all_answers(self): + rv = self.get(self.answers_url()) + self.assertEqual(200, rv.status_code) From 93b669acbd827960d5c27bd1948d6abf35631b88 Mon Sep 17 00:00:00 2001 From: Ahimbisibwe Roland Date: Sat, 18 Aug 2018 17:01:51 +0300 Subject: [PATCH 02/10] [Feature:#159868104] Add a post endpoint to store a question answer --- api/app/controllers/AnswersController.py | 10 +++++++++- tests/feature/test_QuestionAnswers.py | 13 +++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/api/app/controllers/AnswersController.py b/api/app/controllers/AnswersController.py index 23130e6..8dd2dcb 100644 --- a/api/app/controllers/AnswersController.py +++ b/api/app/controllers/AnswersController.py @@ -1,4 +1,4 @@ -from flask import jsonify +from flask import jsonify, request from api.app.models import Question @@ -7,3 +7,11 @@ class AnswersController: def index(cls, question_id): question = Question.find_or_fail(question_id).load("answers") return jsonify(dict(data=question["answers"])) + + @classmethod + def store(cls, question_id): + question = Question.find_or_fail(question_id) + answer = question.answers().create(request.validate({ + "body": "required" + })) + return jsonify(dict(data=answer)), 201 diff --git a/tests/feature/test_QuestionAnswers.py b/tests/feature/test_QuestionAnswers.py index b044bf1..0f1aac8 100644 --- a/tests/feature/test_QuestionAnswers.py +++ b/tests/feature/test_QuestionAnswers.py @@ -24,3 +24,16 @@ def answer_url(self, id): def test_it_fetches_a_list_of_all_answers(self): rv = self.get(self.answers_url()) self.assertEqual(200, rv.status_code) + + def test_add_a_question_answer_returns_a_201_status(self): + rv = self.post(self.answers_url(), dict(body="Some answer")) + self.assertEqual(201, rv.status_code) + + def test_add_a_question_answer_passes(self): + answer = dict(body="Some answer") + rv = self.post(self.answers_url(), answer) + self.assertDictContainsSubset(answer, rv.get_json()["data"]) + + def test_add_a_question_answer_fails_with_invalid_data(self): + rv = self.post(self.answers_url()) + self.assertEqual(rv.status_code, 422) From 106a04ab4a0894763a4712043365e6a50f745a78 Mon Sep 17 00:00:00 2001 From: Ahimbisibwe Roland Date: Sat, 18 Aug 2018 17:57:54 +0300 Subject: [PATCH 03/10] Fix: Convert all route resource ids to integers --- api/core/routing/RouteResource.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/api/core/routing/RouteResource.py b/api/core/routing/RouteResource.py index 32c1f79..1a8baa2 100644 --- a/api/core/routing/RouteResource.py +++ b/api/core/routing/RouteResource.py @@ -38,8 +38,8 @@ def prepare_urls(self, url): parts = str(url).split(".") if len(parts) == 1: self.all_url = parts[0] - self.single_url = f"{parts[0]}/" + self.single_url = f"{parts[0]}/" else: - self.all_url = f"{parts[0]}//{parts[1]}" - self.single_url = f"{self.all_url}/" + self.all_url = f"{parts[0]}//{parts[1]}" + self.single_url = f"{self.all_url}/" return self From 00d0fb395c9443beb19369b01215a085655d7cc1 Mon Sep 17 00:00:00 2001 From: Ahimbisibwe Roland Date: Sat, 18 Aug 2018 18:32:19 +0300 Subject: [PATCH 04/10] Feature:Add the first_or_fail method to ModelCollection The first_or_fail methods returns the first model in a ModelCollection or throws an exception if no models exist --- api/core/exceptions.py | 10 +++++----- api/core/storage/storage.py | 12 +++++++++--- tests/unit/test_Storage.py | 9 ++++++++- 3 files changed, 22 insertions(+), 9 deletions(-) diff --git a/api/core/exceptions.py b/api/core/exceptions.py index 4c947eb..9ad6b75 100644 --- a/api/core/exceptions.py +++ b/api/core/exceptions.py @@ -12,8 +12,8 @@ def __init__(self, errors): class ModelNotFoundException(NotFound): - def __init__(self, table, id): - response = dict( - error=f"Coudnot find a {table} resource with id: {id}" - ) - super().__init__(response=response) + def __init__(self, table=None, id=None): + error = "Couldn't find a given resource" + if table: + error = f"Coudnot find a {table} resource with id: {id}" + super().__init__(response=dict(error=error)) diff --git a/api/core/storage/storage.py b/api/core/storage/storage.py index d848c91..0aec208 100644 --- a/api/core/storage/storage.py +++ b/api/core/storage/storage.py @@ -98,6 +98,12 @@ def first(self): except IndexError: return None + def first_or_fail(self): + first = self.first() + if first: + return first + raise ModelNotFoundException() + def __iter__(self): return iter(self.models) @@ -168,9 +174,9 @@ def find(cls, id): @classmethod def find_or_fail(cls, id): - question = cls.find(id) - if question: - return question + model = cls.find(id) + if model: + return model raise ModelNotFoundException(cls.table_name(), id) @classmethod diff --git a/tests/unit/test_Storage.py b/tests/unit/test_Storage.py index 2494b66..31775b1 100644 --- a/tests/unit/test_Storage.py +++ b/tests/unit/test_Storage.py @@ -1,7 +1,7 @@ from unittest import TestCase from collections import Iterable from api.core.storage import Model, Storage -from api.core.exceptions import ModelException +from api.core.exceptions import ModelException, ModelNotFoundException class Contact(Model): @@ -136,3 +136,10 @@ def test_model_collection_length(self): def test_model_collection_is_iterable(self): User.create(self.attributes) self.assertIsInstance(iter(User.all()), Iterable) + + def test_it_first_or_fail_fails(self): + self.assertRaises(ModelNotFoundException, User.all().first_or_fail) + + def test_it_first_or_fail_passes(self): + User.create(self.attributes) + self.assertEqual(1, len(User.all())) From a5f9981c04dd23939662be40d2e7d93dfe270eca Mon Sep 17 00:00:00 2001 From: Ahimbisibwe Roland Date: Sat, 18 Aug 2018 18:40:59 +0300 Subject: [PATCH 05/10] [Feature:#159868640] Add a get REST end point for a specific answer --- api/app/controllers/AnswersController.py | 11 ++++++++++- api/app/models/__init__.py | 4 ++-- tests/feature/test_QuestionAnswers.py | 5 +++++ 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/api/app/controllers/AnswersController.py b/api/app/controllers/AnswersController.py index 8dd2dcb..697e929 100644 --- a/api/app/controllers/AnswersController.py +++ b/api/app/controllers/AnswersController.py @@ -1,5 +1,5 @@ from flask import jsonify, request -from api.app.models import Question +from api.app.models import Question, Answer class AnswersController: @@ -8,6 +8,15 @@ def index(cls, question_id): question = Question.find_or_fail(question_id).load("answers") return jsonify(dict(data=question["answers"])) + @classmethod + def show(cls, question_id, answer_id): + answer = Answer.where( + question_id=question_id, + id=answer_id + ).first_or_fail() + + return jsonify(dict(data=answer)), 200 + @classmethod def store(cls, question_id): question = Question.find_or_fail(question_id) diff --git a/api/app/models/__init__.py b/api/app/models/__init__.py index 72edf30..4c63da4 100644 --- a/api/app/models/__init__.py +++ b/api/app/models/__init__.py @@ -1,3 +1,3 @@ from .Question import Question - -__all__ = ["Question"] +from .Answer import Answer +__all__ = ["Question", "Answer"] diff --git a/tests/feature/test_QuestionAnswers.py b/tests/feature/test_QuestionAnswers.py index 0f1aac8..7e1a019 100644 --- a/tests/feature/test_QuestionAnswers.py +++ b/tests/feature/test_QuestionAnswers.py @@ -37,3 +37,8 @@ def test_add_a_question_answer_passes(self): def test_add_a_question_answer_fails_with_invalid_data(self): rv = self.post(self.answers_url()) self.assertEqual(rv.status_code, 422) + + def test_get_existing_question_answer_returns_a_200_response(self): + self.post(self.answers_url(), dict(body="Some existing answer")) + rv = self.get(self.answer_url(1)) + self.assertEqual(rv.status_code, 200) From 15e460406dfb0a4f0a28710fcb99f47fb40bff83 Mon Sep 17 00:00:00 2001 From: Ahimbisibwe Roland Date: Sat, 18 Aug 2018 19:04:40 +0300 Subject: [PATCH 06/10] [Feature: #159868276] Add a put endpoint for a question answer --- api/app/controllers/AnswersController.py | 15 ++++++++++----- api/app/models/Answer.py | 4 +++- tests/feature/__init__.py | 3 +++ tests/feature/test_QuestionAnswers.py | 7 +++++++ 4 files changed, 23 insertions(+), 6 deletions(-) diff --git a/api/app/controllers/AnswersController.py b/api/app/controllers/AnswersController.py index 697e929..d03fa24 100644 --- a/api/app/controllers/AnswersController.py +++ b/api/app/controllers/AnswersController.py @@ -10,11 +10,7 @@ def index(cls, question_id): @classmethod def show(cls, question_id, answer_id): - answer = Answer.where( - question_id=question_id, - id=answer_id - ).first_or_fail() - + answer = Answer.by_question_id(question_id, answer_id) return jsonify(dict(data=answer)), 200 @classmethod @@ -24,3 +20,12 @@ def store(cls, question_id): "body": "required" })) return jsonify(dict(data=answer)), 201 + + @classmethod + def update(cls, question_id, answer_id): + answer = Answer.by_question_id(question_id, answer_id).update( + request.validate({ + "body": "required" + })) + + return jsonify(dict(data=answer)), 200 diff --git a/api/app/models/Answer.py b/api/app/models/Answer.py index be8ff66..c287748 100644 --- a/api/app/models/Answer.py +++ b/api/app/models/Answer.py @@ -2,4 +2,6 @@ class Answer(Model): - pass + @classmethod + def by_question_id(cls, qtn_id, ans_id): + return cls.where(question_id=qtn_id, id=ans_id).first_or_fail() diff --git a/tests/feature/__init__.py b/tests/feature/__init__.py index 5b0f64a..3fa5177 100644 --- a/tests/feature/__init__.py +++ b/tests/feature/__init__.py @@ -24,6 +24,9 @@ def post(self, url, json=None): def patch(self, url, json=None): return self.client.patch(**self._make_options(url, json)) + def put(self, url, json=None): + return self.client.put(**self._make_options(url, json)) + def delete(self, url): return self.client.delete(**self._make_options(url)) diff --git a/tests/feature/test_QuestionAnswers.py b/tests/feature/test_QuestionAnswers.py index 7e1a019..a3130b1 100644 --- a/tests/feature/test_QuestionAnswers.py +++ b/tests/feature/test_QuestionAnswers.py @@ -42,3 +42,10 @@ def test_get_existing_question_answer_returns_a_200_response(self): self.post(self.answers_url(), dict(body="Some existing answer")) rv = self.get(self.answer_url(1)) self.assertEqual(rv.status_code, 200) + + def test_it_updates_an_existing_question(self): + self.post(self.answers_url(), dict(body="Some existing answer")) + update = dict(body="Updated answer") + rv = self.put(self.answer_url(1), update) + answer = rv.get_json()["data"] + self.assertDictContainsSubset(update, answer) From ae39bcf249d1e5b7c7e6afd5731ca1f6b634aa07 Mon Sep 17 00:00:00 2001 From: Ahimbisibwe Roland Date: Sat, 18 Aug 2018 19:21:28 +0300 Subject: [PATCH 07/10] [Feature:#159868331] Add a delete endpoint for question_answer --- api/app/controllers/AnswersController.py | 5 +++++ tests/feature/test_QuestionAnswers.py | 8 +++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/api/app/controllers/AnswersController.py b/api/app/controllers/AnswersController.py index d03fa24..e2f4fdd 100644 --- a/api/app/controllers/AnswersController.py +++ b/api/app/controllers/AnswersController.py @@ -29,3 +29,8 @@ def update(cls, question_id, answer_id): })) return jsonify(dict(data=answer)), 200 + + @classmethod + def destroy(cls, question_id, answer_id): + Answer.by_question_id(question_id, answer_id).delete() + return jsonify(dict(message="Answer was successively removed")), 200 diff --git a/tests/feature/test_QuestionAnswers.py b/tests/feature/test_QuestionAnswers.py index a3130b1..ff9c22c 100644 --- a/tests/feature/test_QuestionAnswers.py +++ b/tests/feature/test_QuestionAnswers.py @@ -43,9 +43,15 @@ def test_get_existing_question_answer_returns_a_200_response(self): rv = self.get(self.answer_url(1)) self.assertEqual(rv.status_code, 200) - def test_it_updates_an_existing_question(self): + def test_it_updates_an_existing_question_answer(self): self.post(self.answers_url(), dict(body="Some existing answer")) update = dict(body="Updated answer") rv = self.put(self.answer_url(1), update) answer = rv.get_json()["data"] self.assertDictContainsSubset(update, answer) + + def test_it_deletes_an_existing_question(self): + self.post(self.answers_url(), dict(body="Some existing answer")) + self.delete(self.answer_url(1)) + rv = self.get(self.answer_url(1)) + self.assertEqual(rv.status_code, 404) From b775056a0380a0d708b96e78bef65d1c4b691195 Mon Sep 17 00:00:00 2001 From: Ahimbisibwe Roland Date: Sat, 18 Aug 2018 20:21:25 +0300 Subject: [PATCH 08/10] docs:Add answer endpoints to the README.md --- README.md | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 1fef629..6c792f4 100644 --- a/README.md +++ b/README.md @@ -99,15 +99,19 @@ pytest pytest pytest -v --cov api ``` #### API REST End Points -| End Point | Verb |Use | -| ------------------------|---------------|--------------------------------------| -| /api/v1.0/ |GET |Gets a list of all API resources | -| /api/v1.0/questions |GET |Gets a list of Questions | -|/api/v1.0/questions/id |GET |Gets a Question resource of a given ID| -| /api/v1.0/questions |POST |Stores a Question resource | -|/api/v1.0/questions |PATCH / UPDATE |Updates a Question resource | -|/api/v1.0/questions |DELETE |Deletes a Question resource | - +| End Point | Verb |Use | +| ----------------------------------------------------|------|--------------------------------------| +|`/api/v1.0/` |GET |API index | +|`/api/v1.0/questions` |GET |Gets a list of Questions | +|`/api/v1.0/questions/` |GET |Gets a Question resource of a given ID| +|`/api/v1.0/questions` |POST |Stores a Question resource | +|`/api/v1.0/questions ` |PATCH |Updates a Question resource | +|`/api/v1.0/questions ` |DELETE|Deletes a Question resource | +|`/api/v1.0/questions//answers` |GET |Gets a answers of a specific question | +|`/api/v1.0/questions//answers` |POST |Adds a an answer to a question | +|`/api/v1.0/questions//answers/` |GET |Gets a specific answer | +|`/api/v1.0/questions//answers/` |UPDATE|Updates an existing answer | +|`/api/v1.0/questions//answers/` |DELETE|Deletes an existing answer | #### Built With - [Flask](http://flask.pocoo.org/) A microframework for Python based on Werkzeug, Jinja 2 @@ -116,5 +120,4 @@ pytest pytest -v --cov api A Special thanks goes to 1. [Andela](https://andela.com/) for having given me an opportunity to participate in the boot camp, without them , this application wouldn't be a success. -2. [UI Faces](https://uifaces.co/) for providing free avatar sources that I used in the UI templates - +2. [UI Faces](https://uifaces.co/) for providing free avatar sources that I used in the UI templates \ No newline at end of file From 41ad03f784262d65c461eb5ec0390b40e4224263 Mon Sep 17 00:00:00 2001 From: Ahimbisibwe Roland Date: Sat, 18 Aug 2018 23:22:03 +0300 Subject: [PATCH 09/10] chore: Add travis heroku deploy integration --- .travis.yml | 15 ++++++++++----- Procfile | 1 + requirements.txt | 8 ++++++++ 3 files changed, 19 insertions(+), 5 deletions(-) create mode 100644 Procfile diff --git a/.travis.yml b/.travis.yml index 2780251..b2e0367 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,10 +1,15 @@ language: python python: - - '3.6' +- '3.6' before_script: - - pip3 install -r requirements.txt +- pip3 install -r requirements.txt after_success: - - coveralls +- coveralls script: - - pytest -v --cov api/app --cov-report term-missing - +- pytest -v --cov api/app --cov-report term-missing +deploy: + provider: heroku + api_key: + secure: Eav/qEQN89dyvqBKam746FbeRAo8GQtfjicoxjev482DFHowK3BvieKiHlUzdMdZiAr38uZb2KYD39KdDV/xTMGKENL+/4ADWVywRl4EaNJd+5ufjx8zhQjElZJMpV1mnHCbVLmbE4v3XU65SbibpyjeDvcUMNKYDSjxuRAv0nsWdR/YFYt0s0hTALAGRb/q369+gWtCaX87UGxwUuMmg0uhl9Ke3ktdTStaytymNt4cToQ5V0LQopNs/lQgSb9ZQgLxhBmtjAqKVmyGQzXZc++Poyexeq1bdMA/AcuyyknmeTbYfIW9UNxUxBwCUCVQ/3qMDS4fyNAOYKlERt0agdxlOmQayEEkSgmrd6+iSTR1foena2pHcS2q6Pl9CncIygHezm/9uYPIhg1HmziNQR+peH4q278gSlDh9Z0TOT7NaBIzreTg8ZzrdmolhXEiLFLsX36OGz6HOjec4n8VOcvkDbEb0oQwU3GYTfAMpEk+XgsswSpii5pW75fmklJrr3dHvifekDpcHDhNMU9QCcU+R2LkkZpG3+8g9qsGyG7yoqveIbVO96M8gjvhORRDh7dt+/4GQ9UOkVSifa4q2rUxyXDCLXFlcvI5SwpUgcinvIjCpWRVQBEpeRMbg1Y/KugEtYMtp9AG02+ITLttTUkzmXGiqYKpgsTpgHZKpCM= + app: andela-stackoverflow + on: staging diff --git a/Procfile b/Procfile new file mode 100644 index 0000000..80a980e --- /dev/null +++ b/Procfile @@ -0,0 +1 @@ +web: gunicorn run:app \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index ef10610..385bb6e 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,4 @@ +astroid==2.0.4 atomicwrites==1.1.5 attrs==18.1.0 certifi==2018.8.13 @@ -5,18 +6,25 @@ chardet==3.0.4 click==6.7 coverage==4.0.3 Flask==1.0.2 +gunicorn==19.9.0 idna==2.7 +isort==4.3.4 itsdangerous==0.24 Jinja2==2.10 +lazy-object-proxy==1.3.1 MarkupSafe==1.0 +mccabe==0.6.1 more-itertools==4.3.0 pluggy==0.7.1 py==1.5.4 +pylint==2.1.1 pytest==3.7.1 pytest-cov==2.5.1 python-coveralls==2.9.1 PyYAML==3.13 requests==2.19.1 six==1.11.0 +typed-ast==1.1.0 urllib3==1.23 Werkzeug==0.14.1 +wrapt==1.10.11 From 07def68ecd94b5ebbe9c0b07686ef220dd3e0d7b Mon Sep 17 00:00:00 2001 From: Ahimbisibwe Roland Date: Sun, 19 Aug 2018 00:07:03 +0300 Subject: [PATCH 10/10] docs: Update Readme --- README.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 6c792f4..0c953bd 100644 --- a/README.md +++ b/README.md @@ -71,6 +71,7 @@ While in the terminal in the `UI` directory 3. `npm run watch` or `yarn run watch` to set up a local development server and watch all the files for changes and live reload # API +#### This __api__ is currently hosted on [heroku](https://andela-stackoverflow.herokuapp.com/api/v1.0/) #### Requirements - [Python](https://www.python.org/) A general purpose programming language - [Pip](https://pypi.org/project/pip/) A tool for installing python packages @@ -103,10 +104,10 @@ pytest pytest -v --cov api | ----------------------------------------------------|------|--------------------------------------| |`/api/v1.0/` |GET |API index | |`/api/v1.0/questions` |GET |Gets a list of Questions | -|`/api/v1.0/questions/` |GET |Gets a Question resource of a given ID| |`/api/v1.0/questions` |POST |Stores a Question resource | -|`/api/v1.0/questions ` |PATCH |Updates a Question resource | -|`/api/v1.0/questions ` |DELETE|Deletes a Question resource | +|`/api/v1.0/questions/` |GET |Gets a Question resource of a given ID| +|`/api/v1.0/questions/ ` |PATCH |Updates a Question resource | +|`/api/v1.0/questions` |DELETE|Deletes a Question resource | |`/api/v1.0/questions//answers` |GET |Gets a answers of a specific question | |`/api/v1.0/questions//answers` |POST |Adds a an answer to a question | |`/api/v1.0/questions//answers/` |GET |Gets a specific answer |