Gaspri: How I Built a Gas Station App with Real Government Data
What is Gaspri?
Gaspri is a web application that lets users browse and compare fuel prices from every gas station in Spain in real time. Filter by province, fuel type, and compare prices across major oil companies — all on an interactive map.
You can check it out live at gaspri.hgccarlos.es.
The Starting Point: The Ministry's API
The Spanish Government, through the Ministry for Ecological Transition (MITERD), publishes open data with fuel prices for every gas station in the country. The problem: the API returns a massive JSON with thousands of records, no historical data, no advanced filters, and irregular update cycles.
My goal was to build an intermediate layer that would:
- Automatically sync that data into my own database.
- Store price history for trend analysis.
- Expose a clean API the frontend could consume efficiently.
Architecture
The application is split into two completely independent parts:
Backend (Python + PostgreSQL)
The backend is built in Python and handles all business logic:
- Automatic sync: A workflow orchestrated with n8n triggers synchronization with the Ministry's API on a schedule, updating prices and detecting new stations or changes.
- Database: PostgreSQL stores both current data and the full price history, with optimized indexes for queries by province, company, and fuel type.
- Deduplication: A deduplication system was implemented to avoid duplicate records in the historical data, saving storage and improving query performance.
- REST API: Exposes endpoints for the frontend: gas station listings with filters, province/company analytics, min/max prices, and more.
Frontend (Next.js)
The frontend is built with Next.js and offers:
- Interactive map: Geographic visualization of all stations with company markers, filtered in real time.
- Dynamic filters: By province, fuel type (95 petrol, diesel, LPG…), and company.
- Analytics: Comparative tables showing average prices by province and company.
- News section: Industry energy news integration.
- Fully responsive design: Mobile-first UI with a bottom navigation bar, designed to be used right at the pump.
- Contact form: Integrated with Brevo (formerly Sendinblue) for error reporting and user feedback.
- Anti-spam protection: IP-based rate limiting and a honeypot field on the contact form.
Technical Challenges
1. Data Volume
The Ministry's API returns over 11,000 gas stations per request. Processing, deduplicating, and storing that volume efficiently required:
- Composite indexes in PostgreSQL (
province,date,fuel_type). - Batch processing in the sync pipeline.
- Database-level filtering — never in memory.
2. One-Year Price History
To enable trend analysis, I implemented a backfilling system that reconstructed a full year of price history by combining saved snapshots with the Ministry's API data.
3. Cross-Service Security
Communication between the frontend and backend includes security headers and rate limiting to prevent abuse, without requiring user authentication.
Full Stack
| Layer | Technology | |-------|------------| | Frontend | Next.js, TypeScript, Tailwind CSS | | Backend | Python | | Database | PostgreSQL | | Orchestration | n8n | | Deployment | Docker + Coolify | | Map | Leaflet / MapLibre | | Email / Contact | Brevo |
Conclusion
Gaspri is the project I've invested the most time in recently. It combines government open data consumption, real-time data processing, geographic visualization, and a modern, mobile-friendly frontend. If you're interested in the architecture details or want to get in touch, feel free to reach out via the contact form.