Introducing Station Finder

A Cloudflare hosted single page application.

James Montgomery

4 minute read

TL; DR

After migrating my blog to Cloudflare Pages, I wanted to run an application exclusively using Cloudflare products. Inspiration struck on a journey where I was low on fuel in the car.

Introducing Station Finder

Station Finder is a single-page application. The goal was to provide a means to locate a fuel station.

Access by browsing to funwithfuels.co.uk.

Initially, you select a postcode and choose from a dynamically populated list of station results.

A station selection updates the objects on the page to reflect the station choice.

The following information is retrieved:

  • Summary text;
  • Points of interest;
  • Location co-ordinates;
  • Up to three images;

The UI is responsive to your screen size - a capability provided by Bootstrap. Additionally, a modal exists to display the image in higher resolution.

If the information above is not present, the related elements remain hidden.

Architecture

The application consumes Cloudflare services as follows:

  • Cloudflare hosts DNS for the domain funwithfuels.co.uk.
  • Cloudflare Pages host all files.
  • Cloudflare Workers provide two API endpoints.
  • Cloudflare Workers KV provides the database capability.

JavaScript within the web page executes API lookups based on user choice. These API endpoints are Cloudflare Workers with access to the relevant Workers KV table.

A postcode choice triggers an API request to /api/v1/stations/ with the postcode as a parameter. For example: https://www.funwithfuels.co.uk/api/v1/stations/?thisPostCode=bt5.

Client-side JavaScript processes the content and updates the station picker with the results.

A station choice triggers an API request to /api/v1/station/ with the station ID as a parameter. For example: https://www.funwithfuels.co.uk/api/v1/station/?thisStationID=bt5-1.

Client-side JavaScript processes the content and updates the page with the relevant elements.

Cloudflare Workers KV

I utilise a single namespace for this application. Presently the namespace stores only one type of data. The key is a station ID that has the postcode prepended. The value is a JSON object that contains all information for a station.

  {"name": "BP Spar Belfast Road",
    "summary": {
    "header": "A larger station with a Spar.",
    "points": [
      {
        "Pumps": "Ultimate and regular fuels"
      },
      {
        "Extra": "BPme enabled."
      }
    ]
  },
  "images": [
    {
      "name": "IMG_3018",
      "description": "Station view on your right entering Bangor."
    },
    {
      "name": "IMG_3019",
      "description": "There are a small number of parking spaces around the station."
    },
        {
      "name": "IMG_3017",
      "description": "Station on your left leaving Bangor."
    }
    ]
  }

Of all the limits on the free plan, lists were my only concern. They are limited to 1000 per day.

I would consider but not dwell too much on this. The paid plan includes 1 million lists per month as part of the Workers paid plan (currently $5/month).

Cloudflare Workers

The worker that produces the list of stations based on a postcode operates as follows:

  1. Recieves requests sent to /api/v1/stations/.
  2. Checks for a named parameter thisPostCode.
  3. Checks if the parameter is a valid format.
  4. Then proceeds if there is also only one parameter in the URL. Otherwise, the worker stops here with a rejection response.
  5. Before making a call to Workers KV, the worker looks for an answer in the Cloudflare cache.
  6. If the cache contains a response, the worker returns that result.
  7. If the cache does not contain a response, the worker performs a list operation against the KV namespace for entries starting with the postcode.
  8. A read of each record for the station name.
  9. A JSON response is constructed and returned.

The worker that retrieves the station details operates similarly. The differences are in parameter validation and cache configuration.

I’ve chosen to cache the station list of results for longer to reduce the namespace list operations. The station lookup worker requires only a single read and the free plan limit is presently 100,000 per day.

Cloudflare Pages

The role of Pages is to provide the hosting platform. All front-end files exist here (HTML, JS, images). The only exception is Bootstrap which has CDN hosting provided. The client-side UI and JavaScript will update the source properties of objects on the page in response to API results.

The free plan limits more than accommodate the application.

Conclusion

I’m pleased with how this turned out. The postcode as a decision helped narrow my scope. Otherwise, I might still be figuring out location services! I will consider how I could provide location-based results. I would also like to offer some search filters too.

References

Acknowledgements

  • Thanks to Cloudflare, GitHub for the capabilities in their free plans.
  • Thanks to Bootstrap for their framework and documentation.