A backend REST API built with Flask and PostgreSQL, developed as part of Udacity’s Backend Developer Nanodegree.
It powers a trivia game application, handling questions, categories, search, and quiz logic.
Note: The frontend interface was provided by Udacity and is included only to interact with and test the API.
- Trivia API
- Table of Contents
- 🧩 Project Overview
- ⚙️ Features Implemented
- 🚀 Getting Started
- 🖥️ Running the Application
- 🧪 Running Tests
- 🔍 API Reference
- 🔧 Current Status
- 🗺️ Roadmap
- 🧱 Python 3.12 Upgrade Notes
- 👤 Author
- 📄 License
The Trivia API enables users to:
- View all available trivia categories.
- Browse paginated trivia questions.
- Create and delete questions.
- Search questions by keyword.
- Play a quiz game that returns non-repeated random questions from a selected category.
The backend was built using Flask and SQLAlchemy, following Test-Driven Development (TDD) principles, with unit tests ensuring correctness and reliability.
This project involved building the entire backend RESTful API from a partially completed Flask application. The following features were implemented and fully tested using a Test-Driven Development (TDD) approach:
- Endpoint for All Questions and Categories: Implemented endpoints to fetch all available question categories and a paginated list of all questions.
- Question Management: Developed full Create and Delete functionality for questions in the database, allowing users to add new trivia and remove existing entries.
- Category-Specific Views: Created an endpoint to retrieve all questions belonging to a single, user-selected category.
- Powerful Search: Built a search endpoint that allows users to find questions based on a case-insensitive, partial text match.
- Interactive Quiz Logic: Designed and implemented the core quiz functionality with a stateful endpoint that serves random, non-repeating questions from either "All" categories or a specific one.
- Error Handling: Implemented comprehensive error handlers for common status codes (
404,422,405) to provide clear, consistent JSON error responses.
- Python 3.12.12 (fully tested and recommended)
- Pip
- Node.js & NPM
- PostgreSQL
-
Clone the Repository:
git clone git@github.com:circobit/trivia-api.git cd trivia-api -
Navigate to the Backend Directory:
cd backend -
Create and Activate a Virtual Environment:
python3 -m venv venv source venv/bin/activate -
Install Dependencies:
pip install -r requirements.txt
-
Set up the Database: Create the main database and load the starter data.
dropdb trivia createdb trivia psql trivia < trivia.psql
The frontend application was provided by Udacity for interacting with and testing the API.
To use it locally:
-
Navigate to the Frontend Directory:
cd frontend -
Install Dependencies:
npm install
Both the backend and frontend servers must be running concurrently.
From the backend/ directory:
export FLASK_APP=flaskr
export FLASK_ENV=development
flask runThe backend will be running at http://127.0.0.1:5000/
From the frontend/ directory:
export NODE_OPTIONS=--openssl-legacy-provider && npm startThe frontend will be running at http://127.0.0.1:3000/
This project includes tests located in backend/test_flaskr.py.
Before running tests, create a PostgreSQL database for testing:
psql -U postgres
CREATE DATABASE trivia_test;
\qIf needed, update your credentials in test_flaskr.py:
self.database_user = "your_username"
self.database_password = "your_password"To run the backend test suite, navigate to the backend/ directory and run:
pytest -vTo run the test coverage report, go to the backend/ directory and run:
pytest --cov=flaskr --cov-report=term-missing| Method | Endpoint | Description |
|---|---|---|
| GET | /categories |
Retrieve all categories |
| GET | /questions?page=<n> |
Paginated list of questions |
| POST | /questions |
Add a new question |
| DELETE | /questions/<id> |
Delete a question |
| POST | /questions/search |
Search questions by keyword |
| GET | /categories/<id>/questions |
Get questions in a category |
| POST | /quizzes |
Retrieve random quiz question |
Errors are returned in a consistent JSON format:
{
"success": false,
"error": 404,
"message": "resource not found"
}The API supports 400, 404, 405, and 422 error codes.
- Returns an object containing all available categories.
- cURL Example: curl
http://127.0.0.1:5000/categories - Response Body:
{
"categories": {
"1": "Science",
"2": "Art",
"3": "Geography",
"4": "History",
"5": "Entertainment",
"6": "Sports"
},
"success": true
}- Returns a paginated list of questions (10 per page), a list of all categories, and the total number of questions.
- cURL Example: curl
http://127.0.0.1:5000/questions?page=1 - Response Body:
{
"categories": { ... },
"current_category": "All",
"questions": [
{
"answer": "Tom Cruise",
"category": 5,
"difficulty": 4,
"id": 4,
"question": "What actor did author Anne Rice first denounce, then praise in the role of her beloved Lestat?"
}
],
"success": true,
"total_questions": 19
}- Deletes the question with the given ID.
- curl Example:
curl -X DELETE http://127.0.0.1:5000/questions/5- Response Body:
{
"success": true
}- Creates a new question.
- curl Example:
curl [http://127.0.0.1:5000/questions](http://127.0.0.1:5000/questions) -X POST -H "Content-Type: application/json" -d '{"question":"Who was the first man on the moon?","answer":"Neil Armstrong","difficulty":1,"category":"1"}'- Request Body:
{
"question": "Who was the first man on the moon?",
"answer": "Neil Armstrong",
"difficulty": 1,
"category": "1"
}- Response body:
{
"success": true,
"created": 23,
"total_questions": 20
}- Returns questions that contain the given search term (case-insensitive).
- curl Example:
curl [http://127.0.0.1:5000/questions/search](http://127.0.0.1:5000/questions/search) -X POST -H "Content-Type: application/json" -d '{"searchTerm":"who"}'- Request Body:
{
"searchTerm": "who"
}- Response Body:
{
"current_category": null,
"questions": [
{
"answer": "Muhammad Ali",
"category": 4,
"difficulty": 1,
"id": 9,
"question": "Whose autobiography is entitled 'The Greatest: My Own Story'?"
}
],
"success": true,
"total_questions": 1
}- Returns all questions for a given category.
- curl Example:
curl http://127.0.0.1:5000/categories/1/questions- Response Body:
{
"current_category": 1,
"questions": [
{
"answer": "The Liver",
"category": "1",
"difficulty": 4,
"id": 20,
"question": "What is the heaviest organ in the human body?"
}
],
"success": true,
"total_questions": 3
}- Returns a random, unasked question to continue a quiz game.
- curl Example:
curl [http://127.0.0.1:5000/quizzes](http://127.0.0.1:5000/quizzes) -X POST -H "Content-Type: application/json" -d '{"previous_questions":[20, 21],"quiz_category":{"id":"1","type":"Science"}}'- Request body:
{
"previous_questions": [20, 21],
"quiz_category": {
"id": "1",
"type": "Science"
}
}- Response body with question
{
"success": true,
"question": {
"answer": "Blood",
"category": "1",
"difficulty": 4,
"id": 22,
"question": "Hematology is a branch of medicine involving the study of what?"
}
}- Response Body (end of quiz):
{
"success": true,
"question": null
}The backend currently runs locally using Flask’s development server and connects to a PostgreSQL instance. It has been fully upgraded and tested with Python 3.12.12, achieving 97% code coverage with all tests passing.
The project currently validates CRUD, search, and quiz endpoints through automated unit tests. Future improvements will focus on applying DevOps and SRE best practices to make the service production-ready.
- Upgrade and test the project with Python 3.12
- Replace hardcoded database credentials with environment variables
- Add Dockerfile and docker-compose configuration
- Introduce
/healthzand/readyzendpoints - Expose Prometheus-compatible metrics
- Implement GitHub Actions for automated testing and builds
- Prepare Helm chart for Kubernetes deployment
This project was upgraded from Python 3.9 to Python 3.12.12.
Key updates:
- Updated dependencies for Python 3.12 compatibility.
- Migrated to
pytest 8.xandFlask 3.0with no breaking changes. - Verified functionality and database migrations through the test suite.
- Achieved increased test coverage from 93% → 97%.
Cristian Cevasco
Site Reliability Engineer
GitHub • LinkedIn
This project is licensed under the MIT License.
You are free to use, modify, and distribute this software in accordance with the terms of the license.
