@podium/client
Advanced tools
@@ -11,2 +11,3 @@ /* eslint-disable no-underscore-dangle */ | ||
const _killThreshold = Symbol('podium:httpoutgoing:killthreshold'); | ||
const _redirectable = Symbol('podium:httpoutgoing:redirectable'); | ||
const _reqOptions = Symbol('podium:httpoutgoing:reqoptions'); | ||
@@ -18,2 +19,3 @@ const _resolveCss = Symbol('podium:httpoutgoing:resolvecss'); | ||
const _incoming = Symbol('podium:httpoutgoing:incoming'); | ||
const _redirect = Symbol('podium:httpoutgoing:redirect'); | ||
const _timeout = Symbol('podium:httpoutgoing:timeout'); | ||
@@ -33,2 +35,3 @@ const _success = Symbol('podium:httpoutgoing:success'); | ||
throwable = false, | ||
redirectable = false, | ||
retries = 4, | ||
@@ -105,2 +108,9 @@ timeout, | ||
this[_uri] = uri; | ||
// Whether the user can handle redirects manually. | ||
this[_redirectable] = redirectable; | ||
// When redirectable is true, this object should be populated with redirect information | ||
// such that a user can perform manual redirection | ||
this[_redirect] = null; | ||
} | ||
@@ -212,2 +222,18 @@ | ||
get redirect() { | ||
return this[_redirect]; | ||
} | ||
set redirect(value) { | ||
this[_redirect] = value; | ||
} | ||
get redirectable() { | ||
return this[_redirectable]; | ||
} | ||
set redirectable(value) { | ||
this[_redirectable] = value; | ||
} | ||
pushFallback() { | ||
@@ -214,0 +240,0 @@ this.push(this[_manifest]._fallback); |
@@ -10,3 +10,3 @@ /* eslint-disable no-param-reassign */ | ||
const putils = require('@podium/utils'); | ||
const boom = require('@hapi/boom'); | ||
const { Boom, badGateway } = require('@hapi/boom'); | ||
const Response = require('./response'); | ||
@@ -68,3 +68,3 @@ const utils = require('./utils'); | ||
reject( | ||
boom.badGateway( | ||
badGateway( | ||
`Recursion detected - failed to resolve fetching of podlet ${outgoing.recursions} times`, | ||
@@ -91,5 +91,3 @@ ), | ||
reject( | ||
boom.badGateway( | ||
`No manifest available - Cannot read content`, | ||
), | ||
badGateway(`No manifest available - Cannot read content`), | ||
); | ||
@@ -128,2 +126,6 @@ return; | ||
if (outgoing.redirectable) { | ||
reqOptions.followRedirect = false; | ||
} | ||
const timer = this.histogram.timer({ | ||
@@ -143,3 +145,3 @@ labels: { | ||
// Remote responds but with an http error code | ||
const resError = response.statusCode !== 200; | ||
const resError = response.statusCode >= 400; | ||
if (resError && outgoing.throwable) { | ||
@@ -156,12 +158,12 @@ timer({ | ||
reject( | ||
boom.boomify( | ||
new Error( | ||
`Could not read content. Resource responded with ${response.statusCode} on ${outgoing.contentUri}`, | ||
), | ||
{ | ||
statusCode: response.statusCode, | ||
}, | ||
), | ||
); | ||
const errorMessage = `Could not read content. Resource responded with ${response.statusCode} on ${outgoing.contentUri}`; | ||
const errorOptions = { | ||
statusCode: response.statusCode, | ||
decorate: { | ||
statusCode: response.statusCode, | ||
}, | ||
}; | ||
reject(new Boom(errorMessage, errorOptions)); | ||
return; | ||
@@ -217,2 +219,9 @@ } | ||
if (outgoing.redirectable && response.statusCode >= 300) { | ||
outgoing.redirect = { | ||
statusCode: response.statusCode, | ||
location: response.headers && response.headers.location, | ||
}; | ||
} | ||
outgoing.emit( | ||
@@ -224,2 +233,3 @@ 'beforeStream', | ||
css: outgoing.manifest.css, | ||
redirect: outgoing.redirect, | ||
}), | ||
@@ -248,3 +258,3 @@ ); | ||
reject( | ||
boom.badGateway( | ||
badGateway( | ||
`Error reading content at ${outgoing.contentUri}`, | ||
@@ -251,0 +261,0 @@ error, |
@@ -77,9 +77,16 @@ /* eslint-disable no-underscore-dangle */ | ||
const { manifest, headers } = await this[_resolver].resolve(outgoing); | ||
const { manifest, headers, redirect } = await this[_resolver].resolve( | ||
outgoing, | ||
); | ||
const content = !outgoing.redirect | ||
? Buffer.concat(chunks).toString() | ||
: ''; | ||
return new Response({ | ||
headers, | ||
content: Buffer.concat(chunks).toString(), | ||
content, | ||
css: manifest.css, | ||
js: manifest.js, | ||
redirect, | ||
}); | ||
@@ -86,0 +93,0 @@ } |
@@ -8,2 +8,3 @@ /* eslint-disable no-underscore-dangle */ | ||
const _redirect = Symbol('podium:client:response:redirect'); | ||
const _content = Symbol('podium:client:response:content'); | ||
@@ -15,3 +16,10 @@ const _headers = Symbol('podium:client:response:headers'); | ||
const PodiumClientResponse = class PodiumClientResponse { | ||
constructor({ content = '', headers = {}, css = [], js = [] } = {}) { | ||
constructor({ | ||
content = '', | ||
headers = {}, | ||
css = [], | ||
js = [], | ||
redirect = null, | ||
} = {}) { | ||
this[_redirect] = redirect; | ||
this[_content] = content; | ||
@@ -39,2 +47,6 @@ this[_headers] = headers; | ||
get redirect() { | ||
return this[_redirect]; | ||
} | ||
get [Symbol.toStringTag]() { | ||
@@ -46,2 +58,3 @@ return 'PodiumClientResponse'; | ||
return { | ||
redirect: this[_redirect], | ||
content: this[_content], | ||
@@ -48,0 +61,0 @@ headers: this[_headers], |
{ | ||
"name": "@podium/client", | ||
"version": "4.3.5", | ||
"version": "4.4.0", | ||
"main": "lib/client.js", | ||
@@ -29,7 +29,3 @@ "license": "MIT", | ||
"lint:fix": "eslint --fix .", | ||
"test": "jest .", | ||
"test:filter": "jest -t 'foofoo'", | ||
"test:verbose": "jest --verbose", | ||
"test:coverage": "jest --coverage", | ||
"test:debug": "jest --detectOpenHandles", | ||
"test": "tap test/*.js", | ||
"lint:format": "eslint --fix .", | ||
@@ -48,6 +44,8 @@ "precommit": "lint-staged" | ||
"request": "^2.88.0", | ||
"tap": "^14.10.6", | ||
"ttl-mem-cache": "4.1.0" | ||
}, | ||
"devDependencies": { | ||
"@podium/test-utils": "2.1.0", | ||
"@podium/test-utils": "^2.2.0", | ||
"@sinonjs/fake-timers": "^6.0.0", | ||
"benchmark": "2.1.4", | ||
@@ -63,21 +61,4 @@ "eslint": "6.8.0", | ||
"is-stream": "2.0.0", | ||
"jest": "25.1.0", | ||
"lolex": "5.1.2", | ||
"prettier": "1.19.1" | ||
}, | ||
"jest": { | ||
"coveragePathIgnorePatterns": [ | ||
"test/" | ||
], | ||
"coverageThreshold": { | ||
"global": { | ||
"branches": 99, | ||
"functions": 100, | ||
"lines": 100, | ||
"statements": 100 | ||
} | ||
}, | ||
"testEnvironment": "node", | ||
"clearMocks": true | ||
} | ||
} |
@@ -510,2 +510,10 @@ # @podium/client | ||
```js | ||
try { | ||
const result = await foo.fetch(); | ||
} catch (err) { | ||
// err.statusCode === 404 | ||
} | ||
``` | ||
The error object will reflect the http status code of the remote. In other | ||
@@ -515,2 +523,14 @@ words; if the remote responded with a 404, the `statusCode` in the error object | ||
One exceptional case is when the podlet responds with a `3xx` code. In this case, the error object's `isRedirect` property will be set to true and a property `redirectUrl` will be included. The client itself will not follow redirects, it is up to you to do so. | ||
```js | ||
try { | ||
const result = await foo.fetch(); | ||
} catch (err) { | ||
// err.statusCode === 302 | ||
// err.isRedirect === true | ||
// err.redirectUrl === 'http://redirects.are.us.com' | ||
} | ||
``` | ||
## Podlet update life cycle | ||
@@ -517,0 +537,0 @@ |
83410
2.03%13
-7.14%1524
2.97%641
3.22%11
10%