Skip to content

Commit

Permalink
Data Layer: Save response headers in the action meta when redispatc…
Browse files Browse the repository at this point in the history
…hing
  • Loading branch information
bperson committed May 17, 2017
1 parent 85633f2 commit f2a776f
Show file tree
Hide file tree
Showing 4 changed files with 29 additions and 12 deletions.
13 changes: 7 additions & 6 deletions client/state/data-layer/wpcom-http/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ const fetcherMap = method => get( {
POST: wpcom.req.post.bind( wpcom.req ),
}, method, null );

export const successMeta = data => ( { meta: { dataLayer: { data } } } );
export const failureMeta = error => ( { meta: { dataLayer: { error } } } );
export const successMeta = ( data, headers ) => ( { meta: { dataLayer: { data, headers } } } );
export const failureMeta = ( error, headers ) => ( { meta: { dataLayer: { error, headers } } } );
export const progressMeta = ( { total, loaded } ) => ( { meta: { dataLayer: { progress: { total, loaded } } } } );

export const queueRequest = ( processOutbound, processInbound ) => ( { dispatch }, rawAction, next ) => {
Expand All @@ -54,22 +54,23 @@ export const queueRequest = ( processOutbound, processInbound ) => ( { dispatch
{ path, formData },
query,
method === 'POST' && body,
( error, data ) => {
( error, data, headers ) => {
const {
failures,
nextData,
nextError,
nextHeaders,
shouldAbort,
successes
} = processInbound( action, { dispatch }, data, error );
} = processInbound( action, { dispatch }, data, error, headers );

if ( true === shouldAbort ) {
return null;
}

return !! nextError
? failures.forEach( handler => dispatch( extendAction( handler, failureMeta( nextError ) ) ) )
: successes.forEach( handler => dispatch( extendAction( handler, successMeta( nextData ) ) ) );
? failures.forEach( handler => dispatch( extendAction( handler, failureMeta( nextError, nextHeaders ) ) ) )
: successes.forEach( handler => dispatch( extendAction( handler, successMeta( nextData, nextHeaders ) ) ) );
}
] ) );

Expand Down
8 changes: 6 additions & 2 deletions client/state/data-layer/wpcom-http/pipeline/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,10 @@ import { applyDuplicatesHandlers, removeDuplicateGets } from './remove-duplicate
* @property {ReduxStore} store Redux store
* @property {*} originalData response data from returned network request
* @property {*} originalError response error from returned network request
* @property {*} originalHeaders response headers from returned network request
* @property {*} nextData transformed response data
* @property {*} nextError transformed response error
* @property {*} nextHeaders transformed repsonse headers
* @property {Object[]} failures list of `onFailure` actions to dispatch
* @property {Object[]} successes list of `onSuccess` actions to dispatch
* @property {Boolean} [shouldAbort] whether or not no further processing should occur for request
Expand Down Expand Up @@ -63,19 +65,21 @@ const applyOutboundProcessor = ( outboundData, nextProcessor ) =>
? nextProcessor( outboundData )
: outboundData;

export const processInboundChain = chain => ( originalRequest, store, originalData, originalError ) =>
export const processInboundChain = chain => ( originalRequest, store, originalData, originalError, originalHeaders ) =>
pick(
chain.reduce( applyInboundProcessor, {
originalRequest,
store,
originalData,
originalError,
originalHeaders,
nextData: originalData,
nextError: originalError,
nextHeaders: originalHeaders,
failures: compact( [ originalRequest.onFailure ] ),
successes: compact( [ originalRequest.onSuccess ] ),
} ),
[ 'failures', 'nextData', 'nextError', 'successes', 'shouldAbort' ],
[ 'failures', 'nextData', 'nextError', 'nextHeaders', 'successes', 'shouldAbort' ],
);

export const processOutboundChain = chain => ( originalRequest, store ) =>
Expand Down
12 changes: 8 additions & 4 deletions client/state/data-layer/wpcom-http/pipeline/test/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,44 +35,48 @@ describe( '#processInboundChain', () => {

it( 'should pass through data given an empty chain', () => {
expect(
processInboundChain( [] )( getSites, {}, { value: 1 }, { error: 'bad' } )
processInboundChain( [] )( getSites, {}, { value: 1 }, { error: 'bad' }, {} )
).to.eql( {
failures: [ getSites.onFailure ],
nextData: { value: 1 },
nextError: { error: 'bad' },
nextHeaders: {},
successes: [ getSites.onSuccess ],
} );
} );

it( 'should sequence a single processor', () => {
expect(
processInboundChain( [ responderDoubler ] )( getSites, {}, {}, {} )
processInboundChain( [ responderDoubler ] )( getSites, {}, {}, {}, {} )
).to.eql( {
failures: [ getSites.onFailure, getSites.onFailure ],
nextData: {},
nextError: {},
nextHeaders: {},
successes: [ getSites.onSuccess, getSites.onSuccess ],
} );
} );

it( 'should sequence multiple processors', () => {
expect(
processInboundChain( [ responderDoubler, responderDoubler ] )( getSites, {}, {}, {} )
processInboundChain( [ responderDoubler, responderDoubler ] )( getSites, {}, {}, {}, {} )
).to.eql( {
failures: ( new Array( 4 ) ).fill( getSites.onFailure ),
nextData: {},
nextError: {},
nextHeaders: {},
successes: ( new Array( 4 ) ).fill( getSites.onSuccess ),
} );
} );

it( 'should abort the chain as soon as `shouldAbort` is set', () => {
expect(
processInboundChain( [ aborter, responderDoubler ] )( getSites, {}, {}, {} )
processInboundChain( [ aborter, responderDoubler ] )( getSites, {}, {}, {}, {} )
).to.eql( {
failures: [],
nextData: {},
nextError: {},
nextHeaders: {},
successes: [],
shouldAbort: true,
} );
Expand Down
8 changes: 8 additions & 0 deletions client/state/data-layer/wpcom-http/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,14 @@ export const getData = action => get( action, 'meta.dataLayer.data', null );
*/
export const getError = action => get( action, 'meta.dataLayer.error', null );

/**
* Returns (response) headers data from an HTTP request action if available
*
* @param {Object} action may contain HTTP response headers data
* @returns {?*} headers data if available
*/
export const getHeaders = action => get( action, 'meta.dataLayer.headers', null );

/**
* @typedef {Object} ProgressData
* @property {number} loaded number of bytes already transferred
Expand Down

0 comments on commit f2a776f

Please sign in to comment.