Skip to content
This repository has been archived by the owner on Oct 14, 2020. It is now read-only.

Commit

Permalink
Enabled Feathers authentication on services for services called in
Browse files Browse the repository at this point in the history
GraphQL resolver functions.

Combined changes for graphql and generator-feathers-plus
- Summary:
- params.provider, user & authenticated are copied from the
  graphql service call into the params for every Feathers service call
  in a resolver of BatchLoader.
- If you need additional props to be copied over, include their names in
  `options.extraAuthProps` and `convertArgsToFeathers`.
- For custom resolvers or BatchLoaders, you need to record the
  `convertArgsToFeathers()` call as explained in the details.
- Note you can enable authentication on a Feathers service or graphql
  only if you've run `generate authentication` first.

- Details:
- 'content' param in resolver calls now contains
  provider: params.provider, user: params.user &
  authenticated: params.authenticated (if any) from the /graphql call.
- In `const createdService = createService(options);`
  options.extraAuthProps can pass an array of additional prop names
  to be copied from params to content.
  This allows other auth-related props to be copied into content.
- The previous `convertArgsToFeathers(args, ast, {...})` is recoded to
  `const convertArgs = convertArgsToFeathers([/* prop names */]);`
  `...`
  `convertArgs(args, content, ast, {...})`
  where the `pop names` would normally be the same names used in
  `options.extraAuthProps`. These are additional props to copy into parms
  for the Feathers service call being made in the resolver function.
  • Loading branch information
eddyystop committed Feb 17, 2018
1 parent 7b39938 commit 6a6b351
Show file tree
Hide file tree
Showing 5 changed files with 72 additions and 28 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
# Change Log

## [v1.7.0](https://github.com/feathers-plus/graphql/tree/v1.7.0) (2018-02-06)
[Full Changelog](https://github.com/feathers-plus/graphql/compare/v1.6.1...v1.7.0)

**Merged pull requests:**

- Switched to lodash.merge from lodash.mergeWith [\#6](https://github.com/feathers-plus/graphql/pull/6) ([eddyystop](https://github.com/eddyystop))

## [v1.6.1](https://github.com/feathers-plus/graphql/tree/v1.6.1) (2018-02-05)
[Full Changelog](https://github.com/feathers-plus/graphql/compare/v1.6.0...v1.6.1)

Expand Down
23 changes: 19 additions & 4 deletions lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ class Service {
constructor (options = {}) {
this._options = Object.assign({}, options, runTime); // Define options & convenience methods.
this.sqlDb = undefined;

const props = this._options.extraAuthProps || [];
this._extraAuthProps = Array.isArray(props) ? props : [props];
}

setup (app) {
Expand Down Expand Up @@ -45,6 +48,22 @@ class Service {
throw new BadRequest('A GraphQL query requires a "params.query.query" property. (@feathers-plus/graphql)');
}

const content = {
app: this._app,
batchLoaders: {}, // where batchloaders are stored for this request
provider: params.provider,
user: params.user,
authenticated: params.authenticated,
}

const props = this._options.extraAuthProps || [];

(Array.isArray(props) ? props : [props]).forEach(name => {
if (name in params && !(name in content)) {
content[name] = params[name];
}
});

// Execute GraphQL request.
/*
http://graphql.org/graphql-js/graphql/
Expand All @@ -55,10 +74,6 @@ class Service {
operationName: allows the caller to specify which operation in requestString will be run,
in cases where requestString contains multiple top-level operations.
*/
const content = {
app: this._app,
batchLoaders: {}, // where batchloaders are stored for this request
}
return graphql(this._schema, params.query.query, {}, content)
// GraphQL throws on initialization errors. It swallows others errors.
.catch(err => {
Expand Down
59 changes: 40 additions & 19 deletions lib/run-time/feathers/convert-args-to-feathers.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,43 @@ const merge = require('lodash.merge');
const convertArgsToParams = require('./convert-args-to-params');
const resolversAst = require('graphql-resolvers-ast');

module.exports = function convertArgsToFeathers(args, ast, moreParams = []) {
// GraphQL's `arg` is created with Object.create(null) https://github.com/graphql/express-graphql/issues/177
// Neither args nor objects within args have Object's prototype.
// `mergewith` conscientiously retains this, just as it retains ObjectID objects being instances of ObjectID.
// However some DBs, e.g. NeDB, expect their object params to inherit from Object.
// We therefore have to convert args so it and its inner objects inherit from Object.
// The stringify/parse is safe enough as args is derived from the string params to a GraphQL's type.
args = JSON.parse(JSON.stringify(args));

moreParams = Array.isArray(moreParams) ? moreParams : [moreParams];

const feathersParams = merge(
{ graphql: ast ? resolversAst(ast).resolverPath : true },
{ query: args.query || {} }, // { query } must be defined.
args.params || {},
...moreParams,
)
return convertArgsToParams(feathersParams);
};
module.exports = function convertArgsToFeathers(extraAuthProps = []) {
extraAuthProps = Array.isArray(extraAuthProps) ? extraAuthProps : [extraAuthProps];

return (args, content, ast, moreParams = []) => {
// GraphQL's `arg` is created with Object.create(null) https://github.com/graphql/express-graphql/issues/177
// Neither args nor objects within args have Object's prototype.
// `mergewith` conscientiously retains this, just as it retains ObjectID objects being instances of ObjectID.
// However some DBs, e.g. NeDB, expect their object params to inherit from Object.
// We therefore have to convert args so it and its inner objects inherit from Object.
// The stringify/parse is safe enough as args is derived from the string params to a GraphQL's type.
args = JSON.parse(JSON.stringify(args));

moreParams = Array.isArray(moreParams) ? moreParams : [moreParams];

const feathersParams = merge(
{
provider: content.provider,
user: content.user,
authenticated: content.authenticated,
query: args.query || {},
graphql: ast ? resolversAst(ast).resolverPath : true,
},
args.params || {},
...moreParams,
);

extraAuthProps.forEach(name => {
if (name in content && !(name in feathersParams)) {
feathersParams[name] = content[name];
}
});

return convertArgsToParams(feathersParams);
};
}





10 changes: 5 additions & 5 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
"debug": "3.1.0",
"feathers-hooks-common": "4.5.6",
"graphql": "0.11.7",
"graphql-resolvers-ast": "1.4.0",
"graphql-tools": "2.0.0",
"graphql-type-json": "0.1.4",
"join-monster": "2.0.15",
Expand Down

0 comments on commit 6a6b351

Please sign in to comment.