import { JSONResponseData , ParsedResponseError } from './types' ; import 'isomorphic-fetch' ; /**
 * Return a promise that is resolved or rejected depending on the response's
 * status code.
 */ const _checkStatus = ( res ) : Promise < Response > => { if ( res . status >= 400 ) { return Promise . reject ( res ) ; } return Promise . resolve ( res ) ; } ; const _tryParseJSON = < TResponseType > ( res ) : Promise < TResponseType > => { try { return ( res . json ( ) . catch ( ( ) => Promise . reject ( res ) ) ) ; } catch ( error ) { return Promise . reject ( res ) ; } } ; /**
 * Calls fetch on provided url with default options necessary for interacting
 * with our JSON API. Parses the JSON, provides appropriate headers, and asserts
 * a valid status from the server.
 */ const _fetchJSON = < TResponseType > ( url , { headers = { } , method = 'GET' , mode , ... options } = { } ) : Promise < TResponseType > => { let fetchHeaders = headers as HeadersInit ; if ( method !== 'GET' ) { fetchHeaders = { 'Content-Type' : 'application/json' , ... headers } ; } const fetchOptions = { method , mode , headers : fetchHeaders , credentials : mode === 'cors' ? 'include' : 'same-origin' , ... options } as RequestInit ; return fetch ( url , fetchOptions ) . then ( _checkStatus ) . then < TResponseType > ( _tryParseJSON ) ; } ; const _hasArgumentsError = ( responseData ) : boolean => ! ! ( responseData [ 'error_detail' ] && responseData [ 'error_detail' ] [ 'ARGUMENTS_ERROR' ] ) ; /**
 * Parse v3 errors into an array of objects representing the errors returned by
 * the API. The format of the parsed errors looks like:
 *
 *  {
 *      status_code: 400,
 *      error: 'ERROR_CODE',
 *      description: 'Description of the error
 *  }
 *
 * An ARGUMENTS_ERROR looks like:
 *
 *  {
 *      error: 'ARGUMENTS_ERROR',
 *      description: 'Some of the fields were invalid or something',
 *      argumentErrors: {
 *          attr1: ['INVALID'],
 *          attr2: ['This field is required']
 *      }
 *  }
 *
 */ const _parseError = ( responseData ) : ParsedResponseError => { if ( ! responseData . error ) { return null ; } let error = { error : responseData . error , description : responseData [ 'error_description' ] } as ParsedResponseError ; if ( _hasArgumentsError ( responseData ) ) { error = { ... error , argumentErrors : responseData [ 'error_detail' ] [ 'ARGUMENTS_ERROR' ] } ; } return error ; } ; /**
 * Designed to work with `_checkStatus`, or any function that
 * raises an error on an invalid status. The error raised should have a `response`
 * property with the original response object.
 *
 * Example usage:
 *
 * _fetchJSON('/api/v3/test/path', {'body': someData})
 *     .catch(_catchStatusError)
 *     .then(doSomethingOnSuccess)
 *     .catch(({response, parsedError}) => doSomethingOnError());
 */ const _catchStatusError = ( res ) : Promise < any > => new Promise ( ( resolve , reject ) => { _tryParseJSON ( res ) . then ( ( responseData ) => reject ( { response : res , parsedError : _parseError ( responseData ) } ) ) . catch ( ( ) => reject ( { response : res } ) ) ; } ) ; export interface DefaultApiResponse { [ key ] : any ; } /**
 * Low-level method that makes fetch requests, returning the response formatted as JSON.
 * It parses errors from API v3 and throws exceptions with those errors
 */ const jsonRequest = < TResponseType = DefaultApiResponse > ( url , options ? ) : Promise < TResponseType > => _fetchJSON < TResponseType > ( url , options ) . catch ( _catchStatusError ) ; export default jsonRequest ;