diff --git a/src/dapi/format/JsonDataApi.js b/src/dapi/format/JsonDataApi.js
new file mode 100644
index 0000000..97763b5
--- /dev/null
+++ b/src/dapi/format/JsonDataApi.js
@@ -0,0 +1,91 @@
+/**
+ * Processes DataApi return data as JSON
+ *
+ * Copyright (C) 2014 LoVullo Associates, Inc.
+ *
+ * This file is part of the Liza Data Collection Framework
+ *
+ * Liza is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+var Class = require( 'easejs' ).Class,
+ DataApi = require( '../DataApi' );
+
+
+/**
+ * Processes DataApi return data as JSON
+ */
+module.exports = Class( 'JsonDataApi' )
+ .implement( DataApi )
+ .extend(
+{
+ /**
+ * DataAPI to decorate
+ * @type {DataApi}
+ */
+ 'private _dapi': null,
+
+
+ /**
+ * Decorate provided DataAPI to parse response data as JSON
+ *
+ * @param {DataApi} dapi DataApi to decorate
+ */
+ __construct: function( dapi )
+ {
+ if ( !( Class.isA( DataApi, dapi ) ) )
+ {
+ throw TypeError( "Expecting DataApi" );
+ }
+
+ this._dapi = dapi;
+ },
+
+
+ /**
+ * Proxies request to encapsulated DataApi and parses the result as JSON
+ *
+ * @param {string} data binary data to transmit
+ * @param {function(?Error,*)} callback continuation upon reply
+ *
+ * @return {DataApi} self
+ */
+ 'public request': function( data, callback )
+ {
+ this._dapi.request( data, function( err, resp )
+ {
+ if ( err !== null )
+ {
+ callback( err, null );
+ return;
+ }
+
+ try
+ {
+ var data = JSON.parse( resp );
+ }
+ catch ( e )
+ {
+ // parsing failed
+ callback( e, null );
+ return;
+ }
+
+ callback( null, data );
+ } );
+
+ return this;
+ }
+} );
+
diff --git a/test/dapi/format/JsonDataApiTest.js b/test/dapi/format/JsonDataApiTest.js
new file mode 100644
index 0000000..4ac363a
--- /dev/null
+++ b/test/dapi/format/JsonDataApiTest.js
@@ -0,0 +1,116 @@
+/**
+ * Test case for JSON formatting of API result
+ *
+ * Copyright (C) 2014 LoVullo Associates, Inc.
+ *
+ * This file is part of the Liza Data Collection Framework
+ *
+ * Liza is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+var dapi = require( '../../../' ).dapi,
+ expect = require( 'chai' ).expect,
+ Class = require( 'easejs' ).Class,
+ DataApi = dapi.DataApi,
+ Sut = dapi.format.JsonDataApi;
+
+
+describe( 'JsonDataApi', function()
+{
+ it( 'errors if not provided a DataApi', function()
+ {
+ expect( function()
+ {
+ Sut( {} );
+ } ).to.throw( TypeError, 'DataApi' );
+ } );
+
+
+ it( 'accepts a DataApi', function()
+ {
+ expect( function()
+ {
+ Sut( _createStubDapi( null, '' ) );
+ } ).to.not.throw( TypeError );
+ } );
+
+
+ describe( '.request', function()
+ {
+ it( 'passes data to encapsulated DataApi', function()
+ {
+ var stubs = _createStubDapi( null, '0' ),
+ expected = {};
+
+ Sut( stubs ).request( expected, function() {} );
+ expect( stubs.given ).to.equal( expected );
+ } );
+
+
+ it( 'converts response to JSON', function( done )
+ {
+ var raw = '{"foo": "bar"}';
+ Sut( _createStubDapi( null, raw ) ).request( '', function( err, data )
+ {
+ // should have been converted to JSON
+ expect( data ).to.deep.equal( { foo: 'bar' } );
+ expect( err ).to.equal( null );
+ done();
+ } );
+ } );
+
+
+ it( 'returns error if JSON parsing fails', function( done )
+ {
+ Sut( _createStubDapi( null, 'ERR' ) )
+ .request( '', function( err, data )
+ {
+ expect( err ).to.be.instanceOf( Error );
+ expect( data ).to.equal( null );
+ done();
+ } );
+ } );
+
+
+ it( 'proxy error from encapsulated DataApi', function( done )
+ {
+ var e = Error( 'foo' );
+
+ Sut( _createStubDapi( e, '0' ) )
+ .request( '', function( err, data )
+ {
+ // data should also be cleared out
+ expect( err ).to.equal( e );
+ expect( data ).to.equal( null );
+ done();
+ } );
+ } );
+ } );
+} );
+
+
+function _createStubDapi( err, resp )
+{
+ return Class.implement( DataApi ).extend(
+ {
+ given: null,
+
+ request: function( data, callback )
+ {
+ this.given = data;
+ callback( err, resp );
+ }
+ } )();
+}
+