@cerebral/http
Advanced tools
Comparing version 1.0.1-1502489943822 to 2.0.0-1503592919196
@@ -50,6 +50,7 @@ 'use strict'; | ||
headers: responseHeaders, | ||
result: result | ||
result: result, | ||
isAborted: false | ||
}); | ||
} else { | ||
reject(new _HttpProviderError2.default(xhr.status, responseHeaders, result)); | ||
reject(new _HttpProviderError2.default(xhr.status, responseHeaders, result, xhr.responseText)); | ||
} | ||
@@ -56,0 +57,0 @@ } |
@@ -50,3 +50,3 @@ 'use strict'; | ||
response.isAborted = fileUpload.isAborted; | ||
reject(response); | ||
reject(new _HttpProviderError2.default(xhr.status, (0, _utils.getAllResponseHeaders)(xhr), xhr.responseText, null)); | ||
} | ||
@@ -53,0 +53,0 @@ }; |
@@ -43,3 +43,3 @@ 'use strict'; | ||
function HttpProviderError(status, headers, body) { | ||
function HttpProviderError(status, headers, result) { | ||
var message = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : null; | ||
@@ -54,6 +54,8 @@ var isAborted = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : false; | ||
_this.message = message; | ||
_this.status = status; | ||
_this.headers = headers; | ||
_this.body = body; | ||
_this.isAborted = isAborted; | ||
_this.response = { | ||
status: status, | ||
headers: headers, | ||
result: result, | ||
isAborted: isAborted | ||
}; | ||
return _this; | ||
@@ -68,6 +70,4 @@ } | ||
message: this.message, | ||
status: this.status, | ||
headers: this.headers, | ||
body: this.body, | ||
isAborted: this.isAborted | ||
response: this.response, | ||
stack: this.stack | ||
}; | ||
@@ -74,0 +74,0 @@ } |
@@ -36,6 +36,6 @@ 'use strict'; | ||
case 'error': | ||
reject(new _HttpProviderError2.default(event.currentTarget.status, null, null, 'request error')); | ||
reject(new _HttpProviderError2.default(event.currentTarget.status, getAllResponseHeaders(event.currentTarget), event.currenTarget.responseText, event.currenTarget.responseText || 'request error')); | ||
break; | ||
case 'abort': | ||
reject(new _HttpProviderError2.default(event.currentTarget.status, null, null, 'request abort', true)); | ||
reject(new _HttpProviderError2.default(event.currentTarget.status, getAllResponseHeaders(event.currentTarget), null, 'request abort', true)); | ||
break; | ||
@@ -84,2 +84,6 @@ } | ||
function parseHeaders(rawHeaders) { | ||
if (!rawHeaders) { | ||
return null; | ||
} | ||
var headerPairs = rawHeaders.replace(/\r?\n$/, '').split(/\r?\n/); | ||
@@ -102,6 +106,6 @@ | ||
if (path && path[response.status]) { | ||
return path[response.status](response); | ||
return path[response.status]({ response: response }); | ||
} | ||
return path && path.success ? path.success(response) : response; | ||
return path && path.success ? path.success({ response: response }) : { response: response }; | ||
}) | ||
@@ -108,0 +112,0 @@ // This error will be an instance of HttpError |
{ | ||
"name": "@cerebral/http", | ||
"version": "1.0.1-1502489943822", | ||
"version": "2.0.0-1503592919196", | ||
"description": "HTTP provider for Cerebral 2", | ||
@@ -27,11 +27,11 @@ "main": "lib/index.js", | ||
"dependencies": { | ||
"function-tree": "^1.0.1-1502489943822" | ||
"function-tree": "^1.0.1-1503592919196" | ||
}, | ||
"peerDependencies": { | ||
"cerebral": "^2.0.1-1502489943822" | ||
"cerebral": "^2.1.0-1503592919196" | ||
}, | ||
"devDependencies": { | ||
"cerebral": "^2.0.1-1502489943822", | ||
"cerebral": "^2.1.0-1503592919196", | ||
"xhr-mock": "^1.9.0" | ||
} | ||
} |
496
README.md
@@ -62,3 +62,3 @@ # @cerebral/http | ||
## error | ||
## errors | ||
@@ -73,11 +73,51 @@ ### HttpProviderError | ||
name: 'HttpProviderError', | ||
message: 'Some potential error message', | ||
body: 'Message or response body', | ||
status: 200, | ||
isAborted: false, | ||
headers: {}, | ||
stack: '...' | ||
message: 'Some error message or responseText', | ||
response: { | ||
result: {}, // Parsed responseText | ||
headers: {}, | ||
status: 200, | ||
isAborted: false | ||
}, | ||
stack: '...' | ||
} | ||
``` | ||
This error is available in the following scenarios: | ||
- Inside an action | ||
```js | ||
function someAction ({http}) { | ||
return http.get('/something').catch(error => ...) | ||
} | ||
``` | ||
- Going down an error path | ||
```js | ||
[ | ||
httpGet('/something'), { | ||
success: [], | ||
error: [ | ||
// {error: ...} | ||
] | ||
} | ||
] | ||
``` | ||
- To signal/global catch handlers | ||
```js | ||
const errorCatched = [ | ||
// {error: ...} | ||
displayError | ||
] | ||
Controller({ | ||
catch: new Map([ | ||
[HttpProviderError, errorCatched] | ||
]) | ||
}) | ||
``` | ||
## request | ||
@@ -114,16 +154,47 @@ | ||
## responses | ||
There are two types of responses from the HTTP provider. A **response** and an **error** of type *HttpProviderError*. A **response** will be received on status codes 200-299. Everything else is an **error**. | ||
### response | ||
```js | ||
{ | ||
result: 'the response body', | ||
headers: {...}, | ||
status: 200, | ||
isAborted: false | ||
} | ||
``` | ||
### error | ||
```js | ||
{ | ||
name: 'HttpProviderError', | ||
message: 'Some potential error message', | ||
result: 'Message or response body', | ||
status: 500, | ||
isAborted: false, | ||
headers: {}, | ||
stack: '...' | ||
} | ||
``` | ||
## get | ||
*action* | ||
### action | ||
```js | ||
function someGetAction ({http}) { | ||
return http.get('/items', { | ||
// QUERY object | ||
}, { | ||
// Any options defined in "Custom request" | ||
}) | ||
const query = {} | ||
const options = {} | ||
return http.get('/items', query, options) | ||
.then((response) => { | ||
return {someResponse: response} | ||
}) | ||
.catch((error) => { | ||
return {someError: error} | ||
}) | ||
} | ||
``` | ||
*factory* | ||
### operator | ||
```js | ||
@@ -134,9 +205,32 @@ import {httpGet} from '@cerebral/http/operators' | ||
httpGet('/items'), | ||
/* | ||
PROPS: { | ||
response: {...} | ||
} | ||
*/ | ||
] | ||
``` | ||
// Alternatively with explicit paths | ||
On error this will throw to the signal or global catch handler. | ||
### operator with paths | ||
```js | ||
import {httpGet} from '@cerebral/http/operators' | ||
export default [ | ||
httpGet('/items'), { | ||
success: [], | ||
error: [], | ||
abort: [], // Optional | ||
[STATUS_CODE]: [] // Optionally any status code, ex. 404: [] | ||
success: [ | ||
/* PROPS: {response: {...}} */ | ||
], | ||
error: [ | ||
/* PROPS: {error: {...}} */ | ||
], | ||
abort: [ | ||
/* PROPS: {error: {...}} */ | ||
], | ||
// Optionally any status code, ex. 404: [] | ||
'${STATUS_CODE}': [ | ||
/* PROPS: {response/error: {...}} */ | ||
] | ||
} | ||
@@ -146,27 +240,21 @@ ] | ||
*output* | ||
```javascript | ||
{ | ||
result: 'the response', | ||
status: 200, | ||
// If aborted | ||
isAborted: true | ||
} | ||
``` | ||
## post | ||
*action* | ||
### action | ||
```js | ||
function somePostAction ({http}) { | ||
return http.post('/items', { | ||
// BODY object | ||
}, { | ||
// Any options defined in "Custom request" | ||
}) | ||
const data = {} | ||
const options = {} | ||
return http.post('/items', data, options) | ||
.then((response) => { | ||
return {response} | ||
}) | ||
.catch((error) => { | ||
return {error} | ||
}) | ||
} | ||
``` | ||
*factory* | ||
### operator | ||
```js | ||
@@ -181,4 +269,16 @@ import {httpPost} from '@cerebral/http/operators' | ||
}), | ||
/* | ||
PROPS: { | ||
response: {...} | ||
} | ||
*/ | ||
] | ||
``` | ||
// Alternatively with explicit paths | ||
### operator with paths | ||
```js | ||
import {httpPost} from '@cerebral/http/operators' | ||
import {props} from 'cerebral/tags' | ||
export default [ | ||
httpPost('/items', { | ||
@@ -188,6 +288,16 @@ title: props`itemTitle`, | ||
}), { | ||
success: [], | ||
error: [], | ||
abort: [], // Optional | ||
[STATUS_CODE]: [] // Optionally any status code, ex. 404: [] | ||
success: [ | ||
/* PROPS: {response: {...}} */ | ||
], | ||
error: [ | ||
/* PROPS: {error: {...}} */ | ||
], | ||
abort: [ | ||
/* PROPS: {error: {...}} */ | ||
], | ||
// Optionally any status code, ex. 404: [] | ||
'${STATUS_CODE}': [ | ||
/* PROPS: {response/error: {...}} */ | ||
] | ||
} | ||
@@ -197,27 +307,21 @@ ] | ||
*output* | ||
```javascript | ||
{ | ||
result: 'the response', | ||
status: 200, | ||
// If aborted | ||
isAborted: true | ||
} | ||
``` | ||
## put | ||
*action* | ||
### action | ||
```js | ||
function somePutAction ({http}) { | ||
return http.put('/items/1', { | ||
// BODY object | ||
}, { | ||
// Any options defined in "Custom request" | ||
}) | ||
const data = {} | ||
const options = {} | ||
return http.put('/items/1', data, options) | ||
.then((response) => { | ||
return {response} | ||
}) | ||
.catch((error) => { | ||
return {error} | ||
}) | ||
} | ||
``` | ||
*factory* | ||
### operator | ||
```js | ||
@@ -228,13 +332,34 @@ import {httpPost} from '@cerebral/http/operators' | ||
httpPut('/items', { | ||
// BODY object | ||
// data object | ||
}), | ||
/* | ||
PROPS: { | ||
response: {...} | ||
} | ||
*/ | ||
] | ||
``` | ||
// Alternatively with explicit paths | ||
### operator with paths | ||
```js | ||
import {httpPost} from '@cerebral/http/operators' | ||
export default [ | ||
httpPut('/items', { | ||
// BODY object | ||
// data object | ||
}), { | ||
success: [], | ||
error: [], | ||
abort: [], // Optional | ||
[STATUS_CODE]: [] // Optionally any status code, ex. 404: [] | ||
success: [ | ||
/* PROPS: {response: {...}} */ | ||
], | ||
error: [ | ||
/* PROPS: {error: {...}} */ | ||
], | ||
abort: [ | ||
/* PROPS: {error: {...}} */ | ||
], | ||
// Optionally any status code, ex. 404: [] | ||
'${STATUS_CODE}': [ | ||
/* PROPS: {response/error: {...}} */ | ||
] | ||
} | ||
@@ -244,27 +369,21 @@ ] | ||
*output* | ||
```javascript | ||
{ | ||
result: 'the response', | ||
status: 200, | ||
// If aborted | ||
isAborted: true | ||
} | ||
``` | ||
## patch | ||
*action* | ||
### action | ||
```js | ||
function somePatchAction ({http}) { | ||
return http.patch('/items/1', { | ||
// BODY object | ||
}, { | ||
// Any options defined in "Custom request" | ||
}) | ||
const data = {} | ||
const options = {} | ||
return http.patch('/items/1', data, options) | ||
.then((response) => { | ||
return {response} | ||
}) | ||
.catch((error) => { | ||
return {error} | ||
}) | ||
} | ||
``` | ||
*factory* | ||
### operator | ||
```js | ||
@@ -276,9 +395,31 @@ import {httpPatch} from '@cerebral/http/operators' | ||
httpPatch(string`/items/${props`itemId`}`, state`patchData`), | ||
/* | ||
PROPS: { | ||
response: {...} | ||
} | ||
*/ | ||
] | ||
``` | ||
// Alternatively with explicit paths | ||
### operator with paths | ||
```js | ||
import {httpPatch} from '@cerebral/http/operators' | ||
import {state, props, string} from 'cerebral/tags' | ||
export default [ | ||
httpPatch(string`/items/${props`itemId`}`, state`patchData`), { | ||
success: [], | ||
error: [], | ||
abort: [], // Optional | ||
[STATUS_CODE]: [] // Optionally any status code, ex. 404: [] | ||
success: [ | ||
/* PROPS: {response: {...}} */ | ||
], | ||
error: [ | ||
/* PROPS: {error: {...}} */ | ||
], | ||
abort: [ | ||
/* PROPS: {error: {...}} */ | ||
], | ||
// Optionally any status code, ex. 404: [] | ||
'${STATUS_CODE}': [ | ||
/* PROPS: {response/error: {...}} */ | ||
] | ||
} | ||
@@ -288,27 +429,21 @@ ] | ||
*output* | ||
```javascript | ||
{ | ||
result: 'the response', | ||
status: 200, | ||
// If aborted | ||
isAborted: true | ||
} | ||
``` | ||
## delete | ||
*action* | ||
### action | ||
```js | ||
function someDeleteAction ({http}) { | ||
return http.delete('/items/1', { | ||
// QUERY object | ||
}, { | ||
// Any options defined in "Custom request" | ||
}) | ||
const query = {} | ||
const options = {} | ||
return http.delete('/items/1', query, options) | ||
.then((response) => { | ||
return {response} | ||
}) | ||
.catch((error) => { | ||
return {error} | ||
}) | ||
} | ||
``` | ||
*factory* | ||
### operator | ||
```js | ||
@@ -320,9 +455,31 @@ import {httpPost} from '@cerebral/http/operators' | ||
httpDelete(string`/items/${state`currentItemId`}`), | ||
/* | ||
PROPS: { | ||
response: {...} | ||
} | ||
*/ | ||
] | ||
``` | ||
// Alternatively with explicit paths | ||
### operator with paths | ||
```js | ||
import {httpPost} from '@cerebral/http/operators' | ||
import {state} from 'cerebral/tags' | ||
export default [ | ||
httpDelete(string`/items/${state`currentItemId`}`), { | ||
success: [], | ||
error: [], | ||
abort: [], // Optional | ||
[STATUS_CODE]: [] // Optionally any status code, ex. 404: [] | ||
success: [ | ||
/* PROPS: {response: {...}} */ | ||
], | ||
error: [ | ||
/* PROPS: {error: {...}} */ | ||
], | ||
abort: [ | ||
/* PROPS: {error: {...}} */ | ||
], | ||
// Optionally any status code, ex. 404: [] | ||
'${STATUS_CODE}': [ | ||
/* PROPS: {response/error: {...}} */ | ||
] | ||
} | ||
@@ -332,16 +489,5 @@ ] | ||
*output* | ||
```javascript | ||
{ | ||
result: 'the response', | ||
status: 200, | ||
// If aborted | ||
isAborted: true | ||
} | ||
``` | ||
## uploadFile | ||
*action* | ||
### action | ||
```js | ||
@@ -355,6 +501,12 @@ function someDeleteAction ({http, props}) { | ||
}) | ||
.then((response) => { | ||
return {response} | ||
}) | ||
.catch((error) => { | ||
return {error} | ||
}) | ||
} | ||
``` | ||
*factory* | ||
### operator | ||
```js | ||
@@ -367,13 +519,17 @@ import {httpUploadFile} from '@cerebral/http/operators' | ||
name: state`currentFileName` | ||
}), | ||
}), { | ||
success: [ | ||
/* PROPS: {response: {...}} */ | ||
], | ||
error: [ | ||
/* PROPS: {error: {...}} */ | ||
], | ||
abort: [ | ||
/* PROPS: {error: {...}} */ | ||
], | ||
// Alternatively with explicit paths | ||
httpUploadFile('/uploads', props`file`, { | ||
name: state`currentFileName`, | ||
onProgress: 'some.signal.path' | ||
}), { | ||
success: [], | ||
error: [], | ||
abort: [], // Optional | ||
[STATUS_CODE]: [] // Optionally any status code, ex. 404: [] | ||
// Optionally any status code, ex. 404: [] | ||
'${STATUS_CODE}': [ | ||
/* PROPS: {response/error: {...}} */ | ||
] | ||
} | ||
@@ -383,51 +539,43 @@ ] | ||
*output* | ||
```javascript | ||
{ | ||
result: 'the response', | ||
status: 200, | ||
// If aborted | ||
isAborted: true | ||
} | ||
``` | ||
## abort | ||
You can abort any running request, causing the request to resolve as status code **0** and set an **isAborted** property on the response object. The string is a regexp string. | ||
*action* | ||
### operator with paths | ||
```js | ||
function abortRequest({http}) { | ||
http.abort('/items*') | ||
} | ||
``` | ||
import {httpUploadFile} from '@cerebral/http/operators' | ||
import {state, props} from 'cerebral/tags' | ||
*factory* | ||
```js | ||
import {httpAbort} from '@cerebral/http/operators' | ||
export default [ | ||
httpAbort('/items*') // also supports tags | ||
httpUploadFile('/uploads', props`file`, { | ||
name: state`currentFileName` | ||
}), | ||
/* | ||
PROPS: { | ||
response: {...} | ||
} | ||
*/ | ||
] | ||
``` | ||
## response | ||
## abort | ||
You can abort any running request, causing the request to resolve as status code **0** and set an **isAborted** property on the response object. | ||
```js | ||
function someGetAction ({http}) { | ||
return http.get('/items') | ||
// All status codes between 200 - 300, including 200 | ||
.then((response) => { | ||
response.status // Status code of response | ||
response.result // Parsed response text | ||
// The response headers are returned as an object with lowercase header | ||
// names as keys. Values belonging to the same key are separated by ', '. | ||
response.headers // Parsed response headers | ||
}) | ||
// All other status codes | ||
function searchItems({input, state, path, http}) { | ||
http.abort('/items*') // regexp string | ||
return http.get(`/items?query=${input.query}`) | ||
.then(path.success) | ||
.catch((error) => { | ||
// HttpProviderError | ||
error.message // {status: 500, result: 'response text', headers: {}, isAborted: false} | ||
if (error.isAborted) { | ||
return path.abort() | ||
} | ||
return path.error({error}) | ||
}) | ||
} | ||
export default [ | ||
searchItems, { | ||
success: [], | ||
error: [], | ||
abort: [] | ||
} | ||
] | ||
``` | ||
@@ -434,0 +582,0 @@ |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
72031
612
576