Degree Days

Degree Days

Weather Data for Energy Professionals

Access the Degree Days.net API using Client-Side JavaScript

This page has some sample HTML/JavaScript code showing how to use client-side JavaScript (running in a web browser) to specify a JSON request, send it to our API servers (past the security system), and process the JSON response that comes back.

To use it, just create a new HTML file, copy/paste in the code below, open the file in your browser, and edit/experiment from there.

It's not a full client library (like we have for Java, .NET, and Python), but, thanks to JavaScript's excellent support for JSON, it should be pretty easy to adapt it to suit your needs.

See the JSON API docs for more about specifying the data you want in the JSON request. There are lots of options, and the request included in the JavaScript code below is just a simple example. The JSON docs also explain more about the data you can expect back in the response.

You might also find the JSON API test tool useful for testing different JSON requests and seeing the JSON responses that come back.

An important point before you start: it might not be a good idea to put your API access keys in client-side JavaScript code. Please see the notes below the code sample about keeping your API access keys secret.

Also please note that we have a separate code sample for calling the API with server-side JavaScript in Node.js.

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<title>Degree Days.net API JavaScript Example</title>
<!-- We use crypto-js for the cryptography necessary to get past the API's
security scheme.  See www.degreedays.net/api/javascript#crypto for more. -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.9-1/crypto-js.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.9-1/hmac-sha256.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.9-1/enc-base64.min.js"></script>
<script>

function runDegreeDaysExample(callback) {
  // The test API access keys are described at www.degreedays.net/api/test
  // They will let you access data from the Cape Cod area only.
  // To fetch data from locations worldwide, sign up for a proper API account at
  // www.degreedays.net/api/ and copy your API access keys here.  Though please
  // be careful about putting your API access keys in client-side JavaScript on
  // a public website - see www.degreedays.net/api/javascript#keys for more.
  const accountKey = 'test-test-test';
  const securityKey = 'test-test-test-test-test-test-test-test-test-test-test-test-test';
  const endpoint = 'https://apiv1.degreedays.net/json';
  
  
  
  // ************* STEP 1: Create the request **********************************
  // First we create a JSON request that specifies what we want from the API.
  // See www.degreedays.net/api/json#request for more on this.
  
  // You can fetch data from a station ID, a longitude/latitude position, or a 
  // postal/zip code.
  const testLocation = {
    type: 'PostalCodeLocation',
    postalCode: '02532',
    countryCode: 'US'
  };
  // In this example we fetch both HDD and CDD, using the same breakdown (daily
  // data covering the last 7 days) for both. For more breakdown options see
  // www.degreedays.net/api/json#breakdown
  const breakdown = {
    type: 'DailyBreakdown',
    period: {
      type: 'LatestValuesPeriod',
      numberOfValues: 7
    }
  };
  const locationDataRequest = {
    type: 'LocationDataRequest',
    location: testLocation,
    dataSpecs: {
      // Here we specify 2 DataSpec items: one for HDD and one for CDD.  You
      // can specify up to 100 DataSpec items in one request (e.g. to fetch
      // data in lots of base temperatures).  Give each DataSpec a unique name
      // so you can get the corresponding DataSet from the response.
      myHDD: {
        type: 'DatedDataSpec',
        calculation: {
          type: 'HeatingDegreeDaysCalculation',
          baseTemperature: {
            unit: 'F',
            value: 60
          }
        },
        breakdown: breakdown
      },
      myCDD: {
        type: 'DatedDataSpec',
        calculation: {
          type: 'CoolingDegreeDaysCalculation',
          baseTemperature: {
            unit: 'F',
            value: 70
          }
        },
        breakdown: breakdown
      }
    }
  };
  const fullRequest = {
    securityInfo: {
      endpoint: endpoint,
      accountKey: accountKey,
      timestamp: new Date().toISOString(),
      random: CryptoJS.enc.Hex.stringify(CryptoJS.lib.WordArray.random(12))
    },
    request: locationDataRequest
  };
  const fullRequestJson = JSON.stringify(fullRequest);
  
  
  
  // ************* STEP 2: Send the request to the API *************************
  // Next we sign the JSON request and package everything together into an HTTP
  // request which we send to the Degree Days.net API.  This follows the spec at
  // www.degreedays.net/api/json#send
  const signatureBytes = CryptoJS.HmacSHA256(fullRequestJson, securityKey);
  // The API requires the JSON request and the signature to be base64url encoded.
  function base64urlEncode(unencoded) {
    if (typeof(unencoded) === 'string') {
      unencoded = CryptoJS.enc.Utf8.parse(unencoded);
    }
    return CryptoJS.enc.Base64.stringify(unencoded)
        .replace(/=/g, '').replace(/\+/g, '-').replace(/\//g, '_');
  };
  // Send the HTTP request to the API servers using XMLHttpRequest.
  const params = 'request_encoding=base64url' +
    '&signature_method=HmacSHA256' +
    '&signature_encoding=base64url' +
    '&encoded_request=' + base64urlEncode(fullRequestJson) +
    '&encoded_signature=' + base64urlEncode(signatureBytes);
  const xhr = new XMLHttpRequest();
  xhr.open('POST', endpoint, true);
  xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
  xhr.onload = function() {
    if (xhr.status === 200) {
      var parsedResponse;
      try {
        parsedResponse = JSON.parse(xhr.responseText);
      } catch (error) {
        callback(error);
        return;
      }
      callback(null, parsedResponse);
    } else {
      callback(new Error('Got unexpected HTTP response code ' + xhr.status +
          ': ' + xhr.statusText));
    }
  };
  xhr.onerror = function() {
    callback(new Error("Couldn't connect to the API. It could be that your " +
      "network is down, or something is blocking the connection. Your " +
      "browser's developer-tools console may have more details."));
  };
  xhr.send(params);
};



// ************* STEP 3: Process the response from the API *********************
// The JSON response is explained at www.degreedays.net/api/json#response
function processResponse(error, fullResponse) {
  var html = '';
  if (error) {
    html += error.toString() + '<br/>';
  } else {
    // fullResponse.metadata has some rate limit info, but we are mainly
    // interested in fullResponse.response (a LocationDataResponse in this
    // case).
    const response = fullResponse.response;
    if (response.type === 'Failure') {
      // See www.degreedays.net/api/json#failure for more about failures.
      html += 'Request failure: ' + JSON.stringify(response);
    } else {
      // The response contains a lot of useful info, as shown in the JSON docs
      // at www.degreedays.net/api/json#response
      html += 'Station ID: ' + response.stationId + '<br/>';
      // "myHDD" is the name we gave the HDD DataSpec in our request.
      const hddData = response.dataSets.myHDD;
      html += '<br/>';
      if (hddData.type === 'Failure') {
        html += 'Failure for HDD DataSet: ' + JSON.stringify(hddData) + '<br/>';
      } else {
        html += 'HDD:' + '<br/>';
        for (var i = 0, n = hddData.values.length; i < n; i++) {
          const v = hddData.values[i];
          html += v.d + ': ' + v.v + '<br/>';
        }
      }
      html += '<br/>';
      const cddData = response.dataSets.myCDD;
      if (hddData.type === 'Failure') {
        html += 'Failure for CDD DataSet: ' + JSON.stringify(cddData) + '<br/>';
      } else {
        html += 'CDD:' + '<br/>';
        for (var i = 0, n = cddData.values.length; i < n; i++) {
          const v = cddData.values[i];
          html += v.d + ': ' + v.v + '<br/>';
        }
      }
    }
  }
  document.getElementById('results').innerHTML = html;
};


window.onload = function() {
  runDegreeDaysExample(processResponse);
};

</script>
</head>
<body>
  <h1>Degree Days.net API JavaScript Example</h1>
  <div id="results">Fetching data...</div>
  <p><a href="https://www.degreedays.net/api/javascript">Full docs at
  Degree Days.net website</a>.</p>
</body>
</html>

Dependencies

We use crypto-js for the cryptography necessary to get past the API's security scheme. You can install it using a package manager, or you can do as we did near the top of the code sample above and just add script tags into your HTML to include it from cdnjs.com.

It is possible to avoid all dependencies and do everything we're doing with crypto-js by:

Math.random and atob both have good browser support, but SubtleCrypto is not available in Internet Explorer. It's also more complicated to use than crypto-js. So for these reasons we decided to use crypto-js for our code sample above, but you are of course free to use an alternative approach.

Keeping your API access keys secret

To call the API from your website you will need API access keys. You can use the free test-account keys for development, but in production your website will either need to use:

If your users enter their own Degree Days.net API access keys into your site, it should be easy to keep their keys secure by ensuring that each user can only see/use the keys that they have entered themselves.

But a problem can arise if you are using your own API access keys in client-side JavaScript, as your client-side JavaScript code will automatically be available to anyone who can access your website and knows how to view the source in their browser. You might be able to hide/obfuscate your API access keys a little, but a determined hacker would still be able to find them and use your API account for their own purposes (potentially using up your request units every hour so your API account hits its hourly rate limit and your site can't fetch degree days).

This problem applies to calling any secured API from client-side JavaScript... You can't call a secure API without access keys (or tokens, or a password), and you can't do anything from client-side JavaScript without people being able to view the JavaScript, see exactly what is happening, and then replicate it themselves.

If your website is private to your organization, or used by trusted users only, this might not be something you need to worry about.

For a public website the only really secure approach is to call the Degree Days.net API from your server instead of from client-side JavaScript running in your users' browsers. This way you can keep your API access keys securely on your server where nobody else can access them. We have documentation and code samples showing how to call the API from a server with Java, JSON, .NET, Node.js, Python, PHP, Ruby, and XML.

To put this in perspective, it is a degree-days API, not a banking API or an API for medical records... The worst that can happen is that your API access keys get out and your API account hits its rate limit because of other people using it. It's up to you if you wish to call the Degree Days.net API from client-side JavaScript, we just want you to be aware of this potential issue if you do.

Problems?

Hopefully the example code above, the JSON API docs, and the JSON API test tool will be enough to get you going, but please feel free to email us if you'd like more help.

Higher level integration details

It is also worth reading the higher-level integration guide for tips on the various approaches to integrating with the API. We have helped a lot of businesses integrate their software with our API so we are very familiar with the patterns that work well for common use cases.

Choose your Plan and Sign Up Today!

© 2019 BizEE Software Limited - About | Contact | Privacy | Web Tool | API | Integration Guide | API FAQ | API Sign-Up