Skip to content

Commit

Permalink
feat: allow custom response parser to be provided upon instantiation
Browse files Browse the repository at this point in the history
To enable more extensibility and future proofing, this allows a custom
response parser function to be provided upon instantiation. This will
make it easier for others to make their own parsers if they have the need
and possibly allow the community to contribute improved parsers.

Refs #75
  • Loading branch information
phillipj committed Apr 16, 2017
1 parent a17328c commit 76539c8
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 17 deletions.
17 changes: 17 additions & 0 deletions Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ Options:
- **pin**: optional pin code for the managed user
- **token**: plex.tv authentication token (optional)
- **timeout**: timeout value in milliseconds to use when making requests (optional)
- **responseParser**: custom function to be used parsing all responses from Plex Server (optional)
- **options**: override additional PlexHome options (optional, but recommended for PlexHome)
- **identifier**: A unique client identifier. Default is a `generated uuid v4`. *Note: you should really provide this rather than let it get generated. Every time your app runs, a new "device" will get registered on your Plex account, which can lead to poor performance once hundreds or thousands of them get created. Trust me!*
- **product**: The name of your application. Official Plex examples: `Plex Web`, `Plex Home Theater`, `Plex for Xbox One`. Default `Node.js App`
Expand Down Expand Up @@ -208,6 +209,22 @@ An optional method `initialize()` could be implemented if you need reference to
}
```

## Response parsing

You can provide a custom function responsible for parsing all Plex Server responses if you need to, by providing it in the `responseParser` when instantiating a Plex API client.

The default implementation either parses the JSON in the response from the Plex Server, converts XML to a JavaScript object or returns the response as is, depending on the response Content-Type header.

A response parsing function gets two arguments provided: `response`, `body` and is expected to return a `Promise`.

```js
function myCustomJsonResponseParser(response, body) {
const bodyAsString = body.toString('ut8');

return Promise.resolve(bodyAsString).then(JSON.parse);
}
```

## HTTP API Documentation
For more information about the API capabilities, see the [unofficial Plex API documentation](https://github.com/Arcanemagus/plex-api/wiki). The [PlexInc's desktop client wiki](https://github.com/plexinc/plex-media-player/wiki/Remote-control-API) might also be valueable.

Expand Down
31 changes: 14 additions & 17 deletions lib/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ function PlexAPI(options, deprecatedPort) {
this.managedUser = opts.managedUser;
this.authToken = opts.token;
this.authenticator = opts.authenticator || this._credentialsAuthenticator();
this.responseParser = opts.responseParser || this._defaultResponseParser;
this.options = opts.options || {};
this.options.identifier = this.options.identifier || uuid.v4();
this.options.product = this.options.product || 'Node.js App';
Expand Down Expand Up @@ -160,14 +161,10 @@ PlexAPI.prototype._request = function _request(options) {

return new Promise((resolve, reject) => {
request(reqOpts, function onResponse(err, response, body) {
var resolveValue;

if (err) {
return reject(err);
}

resolveValue = body;

// 403 forbidden when managed user does not have sufficient permission
if (response.statusCode === 403) {
return reject(new Error('Plex Server denied request due to lack of managed user permissions!'));
Expand Down Expand Up @@ -203,19 +200,7 @@ PlexAPI.prototype._request = function _request(options) {
// releasing socket back to the agent connection pool: http://nodejs.org/api/http.html#http_agent_maxsockets
response.on('data', function onData() {});

if (!parseResponse) {
return resolve();
}

if (response.headers['content-type'] === 'application/json') {
resolveValue = JSON.parse(body.toString('utf8'));
} else if (response.headers['content-type'].indexOf('xml') > -1) {
resolveValue = xmlToJSON(body.toString('utf8'), {
attrkey: 'attributes'
});
}

return resolve(resolveValue);
return parseResponse ? resolve(self.responseParser(response, body)) : resolve();
});
});
};
Expand Down Expand Up @@ -273,6 +258,18 @@ PlexAPI.prototype._serverScheme = function _serverScheme() {
return this.port === 443 ? 'https://' : 'http://';
};

PlexAPI.prototype._defaultResponseParser = function _defaultResponseParser(response, body) {
if (response.headers['content-type'] === 'application/json') {
return Promise.resolve(body.toString('utf8')).then(JSON.parse);
} else if (response.headers['content-type'].indexOf('xml') > -1) {
return xmlToJSON(body.toString('utf8'), {
attrkey: 'attributes'
});
}

return Promise.resolve(body);
};

function xmlToJSON(str, options) {
return new Promise((resolve, reject) => {
xml2js.parseString(str, options, (err, jsonObj) => {
Expand Down
15 changes: 15 additions & 0 deletions test/query-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -143,4 +143,19 @@ describe('query()', function() {
});
});
});

describe('response parser', () => {
it('allows response parser to be provided upon client instantiation', () => {
const staticResponseParser = () => Promise.resolve('Response parsing has been overriden');

api = new PlexAPI({
hostname: 'localhost',
responseParser: staticResponseParser
});

return api.query('/').then(result => {
expect(result).to.be('Response parsing has been overriden');
});
});
});
});

0 comments on commit 76539c8

Please sign in to comment.