๐ฐ Building a โTop 10 News Appโ with Flask + Hacker News API
While studying German, I often use news articles as reading practice. But sometimes itโs not easy to access news quickly, especially when I just want a simple list of headlines I can read through. So I decided to build a small project that automatically fetches the latest top stories and displays them in a clean, simple interface. This way, I can check news easily โ and at the same time, learn by building something useful with Flask and an external API.
๐งฑ 1. Project Overview
This is a simple Flask web app that retrieves the Top 10 stories from Hacker News and displays their titles and URLs.
What this project demonstrates:
- Fetching external API data
- JSON parsing
- Flask routing & template rendering
- Passing backend data to HTML
- UI styling using TailwindCSS
Small but perfect for learning API integration.
๐ 2. Project Structure
news_app/
โ
โโโ app.py # Main Flask app
โโโ tempCodeRunnerFile.py # Auto-generated runner file (VS Code)
โโโ templates/
โโโ index.html # Frontend template
๐ What is tempCodeRunnerFile.py?
VS Code automatically generates this file when you run a single file or selected code.
It contains the same logic as app.py but is only used for temporary execution.
I included it here in the blog so the project structure matches my real local folder exactly.
๐ 3. API Used โ Hacker News API
Hacker News provides a free JSON API hosted on Firebase.
- Top stories ID list:
https://hacker-news.firebaseio.com/v0/topstories.json
- Retrieve a single story:
https://hacker-news.firebaseio.com/v0/item/<id>.json
We simply fetch the top stories list and take the first 10 items.
๐ฅ๏ธ 4. Backend Code โ app.py
from flask import Flask, render_template
import requests
app = Flask(__name__)
TOP_STORIES_URL = "https://hacker-news.firebaseio.com/v0/topstories.json"
ITEM_URL = "https://hacker-news.firebaseio.com/v0/item/{}.json"
@app.route("/")
def index():
# 1) Fetch top story IDs
ids = requests.get(TOP_STORIES_URL).json()
# 2) Retrieve the top 10 stories
news_list = []
for item_id in ids[:10]:
item = requests.get(ITEM_URL.format(item_id)).json()
news_list.append({
"title": item.get("title"),
"url": item.get("url")
})
# 3) Render the HTML template
return render_template("index.html", news=news_list)
if __name__ == "__main__":
app.run(debug=True)
๐ 5. tempCodeRunnerFile.py (Auto-generated file)
from flask import Flask, render_template
import requests
app = Flask(__name__)
TOP_STORIES_URL = "https://hacker-news.firebaseio.com/v0/topstories.json"
ITEM_URL = "https://hacker-news.firebaseio.com/v0/item/{}.json"
@app.route("/")
def index():
ids = requests.get(TOP_STORIES_URL).json()
news_list = []
for item_id in ids[:10]:
item = requests.get(ITEM_URL.format(item_id)).json()
news_list.append({
"title": item.get("title"),
"url": item.get("url")
})
return render_template("index.html", news=news_list)
if __name__ == "__main__":
app.run(debug=True)
๐จ 6. Frontend Template โ index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Top News</title>
<!-- Tailwind CSS -->
<script src="https://cdn.tailwindcss.com"></script>
<style>
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700&display=swap');
body { font-family: 'Inter', sans-serif; }
</style>
</head>
<body class="bg-gray-100 min-h-screen py-10 px-4 flex justify-center">
<div class="max-w-2xl w-full bg-white shadow-xl rounded-lg overflow-hidden">
<div class="bg-orange-500 p-6">
<h1 class="text-3xl font-bold text-white text-center">Top News</h1>
<p class="text-orange-200 text-center text-sm mt-1">Hacker News Top 10</p>
</div>
<div class="divide-y divide-gray-100">
{% for item in news %}
<div class="hover:bg-orange-50 transition duration-150">
<a href="{{ item.url }}" target="_blank" class="block p-5 flex items-start">
<span class="flex items-center justify-center w-8 h-8 bg-orange-100 text-orange-600 font-bold rounded-full mr-4 text-sm">
{{ loop.index }}
</span>
<div>
<h2 class="text-lg font-semibold text-gray-800 hover:text-orange-600 mb-1">
{{ item.title }}
</h2>
{% if item.url %}
<p class="text-xs text-gray-400 truncate max-w-md">{{ item.url }}</p>
{% endif %}
</div>
</a>
</div>
{% endfor %}
</div>
{% if not news %}
<div class="p-8 text-center text-gray-500">No news available.</div>
{% else %}
<div class="bg-gray-50 p-4 text-center text-xs text-gray-400">
Data provided by Hacker News API
</div>
{% endif %}
</div>
</body>
</html>
โ๏ธ 7. How to Run
Install dependencies:
pip install flask requests
Run:
python app.py
Open browser:
http://127.0.0.1:5000
๐ 8. What I Learned
- How to work with public APIs
- How to parse JSON properly
- How Flask routing + rendering works
- How to pass API data into HTML templates
- Basic UI building with TailwindCSS
A lightweight but very practical project.
๐ 9. Future Improvements (Easy Tasks)
- Show 20, 30, or 50 top stories
- Display author name and score
- Add โtime agoโ formatting
- Add dark/light mode toggle
- Add search/filter features
Top comments (0)