Hi, I’m Abhinav. This is my FuelSpotter backend, built with Django and DRF.
The goal is simple: you provide a start and end location in the US, and the API returns the driving route plus a cost‑optimized refuel plan, assuming 10 mpg mileage and a 500‑mile max range.
Before I demo it, a quick note on what’s happening behind the scenes and why the first request can be slow.
For routing, I use OSRM to generate the route geometry, distance, and duration.
For geocoding, I use Nominatim to convert place names into coordinates.
Because the provided fuel dataset does not include latitude and longitude for each station, I cannot directly query “stations near the route”.
Instead, I sample a few points along the route and reverse‑geocode them to infer the states the route passes through.
That means the first request can take 10 to 20 seconds depending on external API latency and rate limits.
After that, repeat requests get much faster because routing and geocoding results are cached.
Also, when include_geometry_coordinates is enabled, the response is larger because it includes the full route polyline, so it can add some extra time to serialize and transfer.
If we wanted to optimize this further in a production system, there are two good options.
Option one is to enrich the fuel dataset once during ingestion using a paid or batch geocoder, store station lat/lon, and then query stations near the route corridor. That removes most reverse‑geocoding at runtime.
Option two is a progressive approach: every time we have to call Nominatim, we persist the result in our own database cache. Then we check memory cache first, then DB cache, and only then make an external call. Over time, the DB cache “warms up” without geocoding all stations upfront.
Let me show it working end-to-end in Postman.
First, a quick health check.
Great, status is ok, so the server is up.
Now the main endpoint: POST /api/fuel-routes/.
I’ll plan a route from Dallas, TX to Los Angeles, CA.
I’ll set include_geometry_coordinates to true so the response includes full geometry coordinates and you can draw the route on a map.
Alright, so here’s the response.
There are three parts: route, fuel_stops, and summary.
In route, you’ll see distance, duration, and the GeoJSON LineString geometry, plus a bounding box.
Fuel_stops is the actual plan. Each stop has a stop number, an inferred city and state, the selected price per gallon, how many gallons I’m filling, and the cost.
And summary gives the totals: total distance, total fuel consumed, total fuel cost, and total stops.
To sanity-check the behavior, I’ll run a short route like New York to Philadelphia.
Because the vehicle can go up to 500 miles on a full tank, short trips can require zero stops — and that’s what we see.
And if I run a longer route like New York to Los Angeles, you’ll see multiple stops show up because of the 500‑mile range constraint.
Now the algorithm.
There are two layers: first I map prices onto the route, and then I optimize where to buy fuel.
For mapping: I take the OSRM route geometry, sample points along it, reverse-geocode those points to get the state, and then from my local database I pull the cheapest available price for that state.
That gives me a list of candidate “stations” along the route: distance from start and price per gallon.
For optimization: at each station I look ahead within the 500‑mile reachable window.
If there is a cheaper station reachable, I buy just enough to reach that cheaper station.
If there is no cheaper station within range, I fill up and drive as far as possible.
This greedy look-ahead is a standard strategy for minimizing fuel cost with known prices and a fixed tank capacity.
If you ask about complexity, the optimizer is worst-case O(n^2) in the number of candidate stations n.
But here n is not “all US stations” — it’s the number of sampled route points, which is deliberately small because I sample every couple hundred miles.
So CPU time is tiny. The real latency is the external routing and geocoding calls, and caching is where the big win comes from.
If a company ever needs this to scale to many more stations per route, I can make the optimizer near O(n) using a monotonic stack for next-cheaper lookup and a sliding window for reachability.
Finally, a quick code tour.
In api/views.py, FuelRoutePlanView validates the request, geocodes start/end, fetches the OSRM route, and calls the fuel planning service.
In api/services/routing.py and api/services/geocoding.py, you’ll see the OSRM/Nominatim wrappers plus caching.
In api/services/fuel_planner.py, I sample the route, infer states, map to prices from the local DB, and build the station list.
And in api/services/optimizefuel.py, optimize_fuel applies the greedy decision rule to produce the stop list and total cost.
The fuelPrices.csv import is handled by api/management/commands/import_fuel_prices.py using dedupe and bulk inserts.
Optionally, I also built a small client UI to visualize the route and stops on a map — but the main deliverable is the backend API, and the Postman demo is the core proof.
That’s it. Thanks!