Skip to content
Browse files

Client, tests, Travis and npm set up for Dark Sky API

  • Loading branch information...
0 parents commit 223a963ba6187bc57eb5e855fe5ecd59944e79bd @awestendorf committed Mar 17, 2012
Showing with 423 additions and 0 deletions.
  1. +11 −0 .gitignore
  2. +8 −0 .travis.yml
  3. +22 −0 LICENSE
  4. +12 −0 Makefile
  5. +28 −0 README.md
  6. +4 −0 index.js
  7. +136 −0 lib/client.js
  8. +38 −0 package.json
  9. +164 −0 spec/client_spec.js
11 .gitignore
@@ -0,0 +1,11 @@
+/node_modules/
+.eprj
+.monitor
+*.css
+*.gz
+*.swp
+/build/
+tags
+npm-debug.log
+/lib/compiled/
+docs
8 .travis.yml
@@ -0,0 +1,8 @@
+language: node_js
+node_js:
+ - 0.4
+ - 0.6
+
+notifications:
+ recipients:
+ - aaron.westendorf@gmail.com
22 LICENSE
@@ -0,0 +1,22 @@
+The MIT License (MIT)
+
+Copyright (c) 2012 Aaron Westendorf
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+
12 Makefile
@@ -0,0 +1,12 @@
+SHELL = bash
+
+test:
+ jasmine-node --verbose spec/
+
+check:
+ jshint lib/*.js
+
+docs:
+ docco lib/*.js
+
+.PHONY: test check docs
28 README.md
@@ -0,0 +1,28 @@
+Node.js DarkSky API wrapper
+===========================
+
+[![Build Status](http://travis-ci.org/awestendorf/node-darksky.png)](http://travis-ci.org/awestendorf/node-darksky)
+
+About
+-----
+
+A Node.js module for integrating with the [Dark Sky](http://darkskyapp.com) API. You must acquire an API key to use it.
+
+Installation
+------------
+
+The project is hosted on npm
+
+ npm install darksky
+
+Usage
+-----
+
+Create a client and then call one of the exposed methods
+
+ var darksky = require("darksky");
+ var client = darksky.Client("mykey");
+
+ client.forecast('37.8267','-122.423', console.log, console.error);
+
+
4 index.js
@@ -0,0 +1,4 @@
+
+module.exports = require('./lib/client').Client;
+
+var Client = require('./lib/client').Client;
136 lib/client.js
@@ -0,0 +1,136 @@
+//
+// Contains the implementation of the Dark Sky Client
+//
+// Copyright (c) 2012 Aaron Westendorf. See LICENSE for further details.
+//
+// TODO: License
+//
+var https = require('https');
+
+function Client(api_key)
+{
+ // Creates a new Dark Sky client with a given API key
+ //
+ // The key can be acquired by contacting Dark Sky http://darkskyapp.com/
+ //
+ // @constructor
+ // @param {String} api_key The API key
+ this.api_key = api_key;
+}
+
+Client.prototype.call = function(options, callback, error)
+{
+ // Support function to run an HTTPS query against the API
+ //
+ // @param {Object) options The options to pass to https.request
+ // @param {Function} [callback] The optional callback for the result data
+ // @param {Function} [error] The optional callback for error results
+
+ var req = https.request(options, function(res) {
+ // console.log("status: ", res.statusCode);
+ // console.log("headers: ", res.headers);
+
+ if( callback ) {
+ res.on('data', function(d) {
+ callback( d );
+ });
+ }
+
+ });
+
+ if( error ) {
+ req.on('error', function(e) {
+ error(e);
+ });
+ }
+
+ req.end();
+};
+
+Client.prototype.forecast = function(latitude, longitude, callback, error)
+{
+ // Fetch the forecast for a given latitutde and longitude in decimal
+ // degrees
+ // http://darkskyapp.com/api/forecast.html
+ //
+ // @param {String|Number} latitude The latitude of the forecast position
+ // @param {String|Number} longitude The longitude of the forecast position
+ // @param {Function} [callback] The optional callback function to process the result
+ // @param {Function} [error] The optional callback function to process errors
+
+ var options = {
+ host: 'api.darkskyapp.com',
+ port: 443,
+ path : '/v1/forecast/'+this.api_key+'/'+latitude+','+longitude ,
+ method : 'GET'
+ };
+
+ this.call(options, callback, error);
+};
+
+Client.prototype.brief_forecast = function(latitude, longitude, callback, error)
+{
+ // Fetch the brief forecast for a given latitutde and longitude in decimal
+ // degrees
+ // http://darkskyapp.com/api/forecast.html
+ //
+ // @param {String|Number} latitude The latitude of the forecast position
+ // @param {String|Number} longitude The longitude of the forecast position
+ // @param {Function} [callback] The optional callback function to process the result
+ // @param {Function} [error] The optional callback function to process errors
+
+ var options = {
+ host: 'api.darkskyapp.com',
+ port: 443,
+ path : '/v1/brief_forecast/'+this.api_key+'/'+latitude+','+longitude ,
+ method : 'GET'
+ };
+
+ this.call(options, callback, error);
+};
+
+Client.prototype.precipitation = function(points, callback, error)
+{
+ // Fetch forecasts for multiple points and times. Points should be an
+ // array containing triplets of [latitude, longitute, time], where
+ // latitude and longitude are in decimal degrees, and time is a UNIX
+ // GMT timestamp
+ // http://darkskyapp.com/api/precipitation.html
+ //
+ // @param {Array[]} - a list of [LAT,LON,TIME] to look up the forecast for
+ // @param {Function} [callback] The optional callback function to process the result
+ // @param {Function} [error] The optional callback function to process errors
+
+ points = points.map(function(point) {
+ return point.join(',');
+ });
+
+ var options = {
+ host: 'api.darkskyapp.com',
+ port: 443,
+ path : '/v1/precipitation/'+this.api_key+'/'+points.join(';') ,
+ method : 'GET'
+ };
+
+ this.call(options, callback, error);
+};
+
+Client.prototype.interesting = function(callback, error)
+{
+ // Fetch forecasts for interesting storms happening right now
+ // http://darkskyapp.com/api/interesting.html
+ //
+ // @param {Function} [callback] The optional callback function to process the result
+ // @param {Function} [error] The optional callback function to process errors
+
+ var options = {
+ host: 'api.darkskyapp.com',
+ port: 443,
+ path : '/v1/interesting/'+this.api_key ,
+ method : 'GET'
+ };
+
+ this.call(options, callback, error);
+};
+
+exports.Client = Client;
38 package.json
@@ -0,0 +1,38 @@
+{
+ "name": "darksky",
+ "version": "0.1.0",
+ "description": "Dark Sky API wrapper for nodeJS",
+ "homepage": [
+ "https://github.com/awestendorf/node-darksky"
+ ],
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/awestendorf/node-darksky"
+ },
+ "keywords": [
+ "api",
+ "nodejs",
+ "7digital"
+ ],
+ "author": "Aaron Westendorf <aaron.westendorf@gmail.com> (https://github.com/awestendorf)",
+ "licenses": [
+ "MIT"
+ ],
+ "engines": [
+ "node >= 0.4.7"
+ ],
+ "scripts": {
+ "test": "jasmine-node --verbose spec/"
+ },
+ "main": "index.js",
+ "dependencies": {
+ },
+ "devDependencies": {
+ "docco": "0.3.0",
+ "jasmine-node": "1.0.22",
+ "jshint": "0.3.0"
+ },
+ "contributors": [
+ "Aaron Westendorf <aaron.westendorf@gmail.com> (https://github.com/awestendorf)"
+ ]
+}
164 spec/client_spec.js
@@ -0,0 +1,164 @@
+//
+// Test the Dark Sky Client class
+//
+// Copyright (c) 2012 Aaron Westendorf. See LICENSE for further details.
+//
+
+var Client = require('../lib/client').Client;
+var https = require('https');
+
+describe("Client", function() {
+
+var client;
+
+beforeEach(function() {
+ client = new Client('api_key');
+});
+
+it("should create a client with api key set", function() {
+ expect(client.api_key).toEqual('api_key');
+});
+
+it("should call https request and all optional callbacks", function() {
+ var callback = jasmine.createSpy();
+ var error = jasmine.createSpy();
+ var request = {
+ on : jasmine.createSpy(),
+ end : jasmine.createSpy()
+ };
+ spyOn( callback, "call" );
+ spyOn( error, "call");
+ var request_spy = spyOn( https, "request");
+ request_spy.andReturn( request );
+
+ client.call("options", callback, error);
+ // TODO: jasmine should support this style of call!
+ // expect( https.request ).toHaveBeenCalledWith(["options", Function]);
+
+ // Assert all the calls that would have happened
+ expect( request_spy.argsForCall[0][0] ).toEqual("options");
+ expect( request.on.argsForCall[0][0] ).toEqual("error");
+ expect( request.end ).toHaveBeenCalled();
+
+ // Call the request callback to assert that it registers for data
+ var result = {
+ on : jasmine.createSpy()
+ };
+ request_spy.argsForCall[0][1](result);
+ expect( result.on.argsForCall[0][0] ).toEqual("data");
+
+ // Call the data callback to assert that it calls our callback
+ result.on.argsForCall[0][1]("data");
+ expect( callback ).toHaveBeenCalledWith("data");
+
+ // Call the error callback to assert that it calls our callback
+ request.on.argsForCall[0][1]("error");
+ expect( error ).toHaveBeenCalledWith("error")
+});
+
+it("should call https request without optional callbacks", function() {
+ var callback = jasmine.createSpy();
+ var error = jasmine.createSpy();
+ var request = {
+ on : jasmine.createSpy(),
+ end : jasmine.createSpy()
+ };
+ var request_spy = spyOn( https, "request");
+ request_spy.andReturn( request );
+
+ client.call("options");
+ // TODO: jasmine should support this style of call!
+ // expect( https.request ).toHaveBeenCalledWith("options", Function);
+
+ // Assert all the calls that would have happened
+ expect( request_spy.argsForCall[0][0] ).toEqual("options");
+ expect( request.on ).not.toHaveBeenCalled();
+ expect( request.end ).toHaveBeenCalled();
+
+ // Call the request callback to assert that it doesnt register for data
+ var result = {
+ on : jasmine.createSpy()
+ };
+ request_spy.argsForCall[0][1](result);
+ expect( result.on ).not.toHaveBeenCalled();
+
+ // Call the error callback to assert that it doesnt call our callback
+ expect( request.on ).not.toHaveBeenCalled();
+});
+
+it("should fetch the forecast", function()
+{
+ var call = spyOn( client, "call" );
+ client.forecast("3.14", "1.42", "callback", "error");
+
+ expect( call ).toHaveBeenCalledWith(
+ {
+ host : "api.darkskyapp.com",
+ port : 443,
+ path : "/v1/forecast/api_key/3.14,1.42",
+ method : 'GET'
+ }, "callback", "error"
+ );
+});
+
+it("should fetch the brief forecast", function()
+{
+ var call = spyOn( client, "call" );
+ client.brief_forecast("3.14", "1.42", "callback", "error");
+
+ expect( call ).toHaveBeenCalledWith(
+ {
+ host : "api.darkskyapp.com",
+ port : 443,
+ path : "/v1/brief_forecast/api_key/3.14,1.42",
+ method : 'GET'
+ }, "callback", "error"
+ );
+});
+
+it("should fetch the precipitation for a single location", function()
+{
+ var call = spyOn( client, "call" );
+ client.precipitation([["3.14", "1.42", "now"]], "callback", "error");
+
+ expect( call ).toHaveBeenCalledWith(
+ {
+ host : "api.darkskyapp.com",
+ port : 443,
+ path : "/v1/precipitation/api_key/3.14,1.42,now",
+ method : 'GET'
+ }, "callback", "error"
+ );
+});
+
+it("should fetch the precipitation for multiple locations", function()
+{
+ var call = spyOn( client, "call" );
+ client.precipitation([["3.14", "1.42", "now"], ["4.23", "-7.58", "soon"]], "callback", "error");
+
+ expect( call ).toHaveBeenCalledWith(
+ {
+ host : "api.darkskyapp.com",
+ port : 443,
+ path : "/v1/precipitation/api_key/3.14,1.42,now;4.23,-7.58,soon",
+ method : 'GET'
+ }, "callback", "error"
+ );
+});
+
+it("should fetch interesting weather", function()
+{
+ var call = spyOn( client, "call" );
+ client.interesting("callback", "error");
+
+ expect( call ).toHaveBeenCalledWith(
+ {
+ host : "api.darkskyapp.com",
+ port : 443,
+ path : "/v1/interesting/api_key",
+ method : 'GET'
+ }, "callback", "error"
+ );
+});
+
+});

0 comments on commit 223a963

Please sign in to comment.
Something went wrong with that request. Please try again.