Bob Graham

The Bob Graham 24 Hour Club

BGR Calculator API

The code behind the schedule calculator is available to third parties via a simple API.

The server side code relies on a request from a form with specific “named” fields. The bare bones of such a form is shown below with instructions about expected values in the comment for each element. It will be noted that the same value is used for the “id” and “name” of each element: FormData uses the “name”, Javascript code references the “id”. Just consistent to have the two the same.


<form id='calcForm'>
    <fieldset>
        <input type='datetime-local' id='start_time' name='start_time'>

        <input type="range" id="schedule" name="schedule" title='Schedule' min="11.0" max="24.0" step="0.25" value="23.5" >

        <select id="direction" name="direction" title='Direction' placeholder = 'Direction'>
            <option value="">Direction</option>
            <option value="0">Clockwise</option>
            <option value="1">Anti-clockwise</option>
        </select>

        <select id="order" name="order" title='Option' placeholder = 'Route Option'>
            <option value="">Route Option</option>
            <option value="0">Sergeant Man first</option>
            <option value="1">High Raise first</option>
        </select>

        <select id="rocky" name="rocky" title='Rocky' placeholder="Rocky">
            <option value="0">Rocky</option>
            <option value="0">0%</option>
            <!-- etc. Values should be a percentage, i.e. "0.05" for 5%, etc. -->
        </select>

        <input type="range" id="road_1" name="road_1" title='Road' min="0" max="15" value="15" >

        <input type="range" id="road_2" name="road_2" title='Road' min="0" max="15" value="15" >

        <input type="range" id="road_3" name="road_3" title='Road' min="0" max="15" value="15" >

        <input type="range" id="road_4" name="road_4" title='Road' min="0" max="15" value="15" >
    </fieldset>
    <input type="submit" id = "submit" name="submit" value="Submit" />

</form>

Then as part of the first block of code, there can’t be anything before imports, in yourscript.js put:

import Bgr from "http://bobgrahamclub.org.uk/api/v1/bgr.js";

The module does not define a namespace so it’s up to you to define one, in this case it’s “Bgr”.

It’s now a matter of adding an event listener to the form and using the inbuilt FormData functionality to retrieve the data from the form, pull values from the FormData object into a new one and send that via the interface call. The API call creates the body to send to the calculator, there is no need to convert to a JSON stringified object.

Object.fromEntries() is OK here since we don't allow multiple selections in select inputs nor use checkboxes where the user can select multiple items. See the accepted answer on this StackOverflow thread on how to handle that.


const myForm = document.getElementById('calcForm');
form.addEventListener('submit', function(e) {
    e.preventDefault();

    // Get the form values and convert them into a standard object.
    const data = new FormData(myForm),
        message = Object.fromEntries(data);

    // Now send it and handle the server's response.
    Bgr.calculator(message)
        .then((response) => {
            const data = JSON.stringify(response);
            yourResponseHandler(data);
        })
        .catch((error) => console.error(`There was a problem with Bgr.calculator:  ${error}`));
});

The block below shows the valid properties for the message object. All other properties are ignored.


        const message = {
            start_time: 2026-02-14T18:00,  // Must be ISO-8601 format
            schedule: 23,      // Between 12 & 24. Write partial hours as 22.5, etc.
            direction: "clockwise", // or "anticlockwise"
            order: 0,    // 0 = Sergeant Man first, 1 = High Raise first.
            rocky: 0,  // valid values are 0 - 20, default is 0
            road_1: 15, // valid values are 0-15 for all four road_x fields. Default is 15
            road_2: 15,
            road_3: 15,
            road_4: 15
        };