DEV Community

Cover image for My project 6 : Top 10 News App(with Flask + Hacker News API)
Sabin Sim
Sabin Sim

Posted on

My project 6 : Top 10 News App(with Flask + Hacker News API)

๐Ÿ“ฐ 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
Enter fullscreen mode Exit fullscreen mode

๐Ÿ“ 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
Enter fullscreen mode Exit fullscreen mode
  • Retrieve a single story:
https://hacker-news.firebaseio.com/v0/item/<id>.json
Enter fullscreen mode Exit fullscreen mode

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)
Enter fullscreen mode Exit fullscreen mode

๐Ÿ“„ 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)
Enter fullscreen mode Exit fullscreen mode

๐ŸŽจ 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>
Enter fullscreen mode Exit fullscreen mode

โš™๏ธ 7. How to Run

Install dependencies:

pip install flask requests
Enter fullscreen mode Exit fullscreen mode

Run:

python app.py
Enter fullscreen mode Exit fullscreen mode

Open browser:

http://127.0.0.1:5000
Enter fullscreen mode Exit fullscreen mode

๐Ÿ“š 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)