Permalink
Browse files

0.1.0

  • Loading branch information...
0 parents commit 033994290c449388536601462ba27fc1a27f7684 @braintreeps braintreeps committed Aug 24, 2010
@@ -0,0 +1,59 @@
+## Overview
+
+This is a node.js library for integrating with the Braintree gateway. It is a work in progress, very much alpha. Feedback is appreciated.
+It can be used in the sandbox environment, [contact us](mailto:support@getbraintree.com) if you're interested in using
+it in production.
+
+## Installing
+
+* clone this repo somewhere in your require.paths
+* require 'braintree-node/lib/braintree'
+* npm coming soon!
+
+## Dependencies
+
+* node 0.2.0
+* underscore.js
+
+## Quick Start
+
+ var sys = require('sys'),
+ _ = require('underscore')._,
+ braintree = require('braintree-node/lib/braintree');
+
+ var gateway = braintree.connect({
+ environment: braintree.Environment.Sandbox,
+ merchantId: 'your_merchant_id',
+ publicKey: 'your_public_key',
+ privateKey: 'your_private_key'
+ });
+
+ gateway.transaction.sale(
+ {
+ amount: '5.00',
+ creditCard: {
+ number: '5105105105105100',
+ expirationDate: '05/12'
+ }
+ },
+ function (err, response) {
+ if (err) {
+ sys.puts(err.message);
+ return;
+ }
+
+ if (response.success) {
+ sys.puts('Transaction id: ' + response.transaction.id);
+ sys.puts('Transaction status: ' + response.transaction.status);
+ sys.puts('Transaction amount: ' + response.transaction.amount);
+ } else {
+ if (response.transaction) {
+ sys.puts('Transaction status: ' + response.transaction.status);
+ } else {
+ _.each(response.errors.deepErrors(), function (error) {
+ sys.puts(error.message);
+ });
+ }
+ }
+ }
+ );
@@ -0,0 +1,6 @@
+task :default => :spec
+
+desc "run the specs"
+task :spec do
+ sh "vows"
+end
@@ -0,0 +1,24 @@
+var sys = require("sys"),
+ Config = require("./braintree/config").Config,
+ Environment = require("./braintree/environment").Environment,
+ Gateway = require("./braintree/gateway").Gateway,
+ TransactionGateway = require("./braintree/transaction_gateway").TransactionGateway;
+ AuthenticationError = require("./braintree/exceptions/authentication_error").AuthenticationError,
+ errorTypes = require("./braintree/exceptions/error_types");
+
+if (process.version !== 'v0.2.0') {
+ sys.puts('WARNING: node.js version ' + process.version + ' has not been tested with the braintree library');
+}
+
+var connect = function(config) {
+ var gateway = Gateway(Config(config));
+ return {
+ transaction: TransactionGateway(gateway)
+ };
+};
+
+exports.connect = connect;
+exports.version = '0.1.0';
+exports.AuthenticationError = AuthenticationError;
+exports.Environment = Environment;
+exports.errorTypes = errorTypes;
@@ -0,0 +1,11 @@
+var Config = function (rawConfig) {
+ return {
+ environment: rawConfig.environment,
+ merchant_id: rawConfig.merchantId,
+ public_key: rawConfig.publicKey,
+ private_key: rawConfig.privateKey,
+ baseMerchantPath: '/merchants/' + rawConfig.merchantId
+ };
+};
+
+exports.Config = Config;
@@ -0,0 +1,13 @@
+var _ = require('underscore')._;
+
+var CreditCard = function (attributes) {
+ var that = {};
+ _.each(attributes, function (val, key) {
+ that[key] = val;
+ });
+ that.maskedNumber = that.bin + '******' + that.last4;
+
+ return that;
+};
+
+exports.CreditCard = CreditCard;
@@ -0,0 +1,13 @@
+var Environment = function (server, port, ssl) {
+ return {
+ server: server,
+ port: port,
+ ssl: ssl
+ }
+};
+
+Environment.Development = Environment('localhost', '3000', false);
+Environment.Sandbox = Environment('sandbox.braintreegateway.com', '443', true);
+Environment.Production = Environment('www.braintreegateway.com', '443', true);
+
+exports.Environment = Environment;
@@ -0,0 +1,16 @@
+var ValidationErrorsCollection = require('./validation_errors_collection').ValidationErrorsCollection,
+ Transaction = require('./transaction').Transaction;
+
+var ErrorResponse = function (attributes) {
+ var that = {};
+ _.each(attributes, function (val, key) {
+ that[key] = val;
+ });
+ that.success = false;
+ that.errors = ValidationErrorsCollection(that.errors);
+ if (that.transaction) that.transaction = Transaction(that.transaction);
+
+ return that;
+};
+
+exports.ErrorResponse = ErrorResponse;
@@ -0,0 +1,10 @@
+var errorTypes = require('./error_types');
+
+var AuthenticationError = function() {
+ return {
+ message: 'Authentication Error',
+ type: errorTypes.authenticationError
+ };
+};
+
+exports.AuthenticationError = AuthenticationError;
@@ -0,0 +1,2 @@
+exports.authenticationError = 'authenticationError';
+exports.unexpectedError = 'unexpectedError';
@@ -0,0 +1,10 @@
+var errorTypes = require('./error_types');
+
+var UnexpectedError = function (message) {
+ return {
+ message: message,
+ type: errorTypes.unexpectedError
+ };
+};
+
+exports.UnexpectedError = UnexpectedError;
@@ -0,0 +1,10 @@
+var Http = require('./http').Http;
+
+var Gateway = function(config) {
+ return {
+ config: config,
+ http: Http(config)
+ };
+};
+
+exports.Gateway = Gateway;
@@ -0,0 +1,51 @@
+var sys = require('sys'),
+ http = require('http'),
+ Buffer = require('buffer').Buffer,
+ base64 = require('../vendor/base64.node'), // http://github.com/pkrumins/node-base64.git @ 10e79a13
+ braintree = require('../braintree'),
+ AuthenticationError = require('./exceptions/authentication_error').AuthenticationError,
+ UnexpectedError = require('./exceptions/unexpected_error').UnexpectedError;
+
+var Http = function (config) {
+ var my = {
+ config: config
+ };
+
+ return {
+ post: function (url, body, callback) {
+ var client = http.createClient(
+ my.config.environment.port,
+ my.config.environment.server,
+ my.config.environment.ssl
+ );
+ var requestBody = JSON.stringify(body);
+ var request = client.request('POST', my.config.baseMerchantPath + url, {
+ 'Content-Length': requestBody.length.toString(),
+ 'Authorization': base64.encode(new Buffer(my.config.public_key + ':' + my.config.private_key)),
+ 'X-ApiVersion': '2',
+ 'Accept': 'application/json',
+ 'Content-Type': 'application/json',
+ 'User-Agent': 'client Node ' + braintree.version
+ });
+ request.write(requestBody);
+ request.end();
+ request.on('response', function (response) {
+ var body = '';
+ response.on('data', function (responseBody) {
+ body += responseBody;
+ });
+ response.on('end', function () {
+ if (response.statusCode == 401) {
+ callback(AuthenticationError(), null);
+ } else if (response.statusCode == 200 || response.statusCode == 201 || response.statusCode == 422) {
+ callback(null, JSON.parse(body));
+ } else {
+ callback(UnexpectedError('Unexpected HTTP response: ' + response.statusCode), null);
+ }
+ });
+ });
+ }
+ };
+};
+
+exports.Http = Http;
@@ -0,0 +1,14 @@
+var _ = require('underscore')._,
+ CreditCard = require('./credit_card').CreditCard;
+
+var Transaction = function (attributes) {
+ var that = {};
+ _.each(attributes, function (val, key) {
+ that[key] = val;
+ });
+ that.creditCard = CreditCard(that.creditCard);
+
+ return that;
+};
+
+exports.Transaction = Transaction;
@@ -0,0 +1,35 @@
+var Transaction = require('./transaction').Transaction,
+ ErrorResponse = require('./error_response').ErrorResponse;
+
+var TransactionGateway = function(gateway) {
+ var my = {
+ gateway: gateway
+ };
+
+ var create = function(attributes, callback) {
+ my.gateway.http.post('/transactions', {transaction: attributes}, function (err, response) {
+ if (err) return callback(err, response);
+
+ if (response.transaction) {
+ response.success = true;
+ response.transaction = Transaction(response.transaction);
+ callback(null, response);
+ }
+ else if (response.apiErrorResponse) {
+ callback(null, ErrorResponse(response.apiErrorResponse));
+ }
+ else {
+ // shouldn't happen
+ }
+ });
+ };
+
+ return {
+ sale: function(attributes, callback) {
+ attributes.type = 'sale';
+ return create(attributes, callback);
+ }
+ };
+};
+
+exports.TransactionGateway = TransactionGateway;
@@ -0,0 +1,9 @@
+var ValidationError = function (error) {
+ return {
+ attribute: error.attribute,
+ code: error.code,
+ message: error.message
+ };
+};
+
+exports.ValidationError = ValidationError;
@@ -0,0 +1,54 @@
+var _ = require('underscore')._,
+ ValidationError = require('./validation_error').ValidationError;
+
+var ValidationErrorsCollection = function (errorAttributes) {
+ var my = {
+ validationErrors: {},
+ errorCollections: {}
+ };
+
+ var buildErrors = function (errors) {
+ _.each(errors, function (item) {
+ my.validationErrors[toCamel(item.attribute)] = ValidationError(item);
+ });
+ };
+
+ var toCamel = function (word) {
+ return word.replace(/(\_[a-z])/g, function($1) {
+ return $1.toUpperCase().replace('_','');
+ });
+ };
+
+ _.each(errorAttributes, function (val, key) {
+ if (key === 'errors') {
+ buildErrors(val);
+ } else {
+ my.errorCollections[key] = ValidationErrorsCollection(val);
+ }
+ });
+
+ return {
+ deepErrors: function () {
+ var deepErrors = [];
+ _.each(my.validationErrors, function (val, key) {
+ deepErrors.push(val);
+ });
+
+ _.each(my.errorCollections, function (val, key) {
+ deepErrors = deepErrors.concat(val.deepErrors());
+ });
+
+ return deepErrors;
+ },
+
+ for: function (name) {
+ return my.errorCollections[name];
+ },
+
+ on: function (name) {
+ return my.validationErrors[name];
+ }
+ };
+};
+
+exports.ValidationErrorsCollection = ValidationErrorsCollection;
Binary file not shown.
@@ -0,0 +1,29 @@
+require('../spec_helper');
+var braintree = require('../../lib/braintree');
+
+vows.describe('Braintree').addBatch({
+ 'version': {
+ topic: braintree.version,
+ 'is 0.1.0': function (version) {
+ assert.equal(version, '0.1.0');
+ }
+ },
+
+ 'AuthenticationError': {
+ 'for invalid credentials': {
+ topic: function () {
+ var gateway = braintree.connect({
+ environment: braintree.Environment.Development,
+ merchantId: 'invalid',
+ publicKey: 'invalid',
+ privateKey: 'invalid'
+ });
+ gateway.transaction.sale({}, this.callback);
+ },
+ 'returns the AuthenticationError': function (err, response) {
+ assert.equal(err.type, braintree.errorTypes.authenticationError);
+ }
+ }
+ }
+}).export(module);
+
Oops, something went wrong.

0 comments on commit 0339942

Please sign in to comment.