Search code examples
graphqlapollo-serverfeathersjs

How do we use hook for Feathersjs + Apollo v2?


Having problem setting up hook for Feathersjs + Apollo v2. Main reason needing it is for authorization.

src/services/graphql/graphql.service.js:65
  service.hooks(hooks);
      ^
TypeError: Cannot read property 'hooks' of undefined

Following is my codes for setting up Apollo v2 in Feathersjs service. Since it does not carry a model, I'm not sure what's the correct way to set up the hook.

const { ApolloServer, gql } = require('apollo-server-express');
const hooks = require('./graphql.hooks');

module.exports = function (app) {

  const typeDefs = gql`
    type Query {
      hello: String
    }
  `;

  const resolvers = {
    Query: {
      hello: () => 'hello world'
    }
  };

  const server = new ApolloServer({
    typeDefs: typeDefs,
    resolvers: resolvers,
    context: ({req, res}) => ({
      provider: req.feathers.provider,
      headers: req.feathers.headers,
      token: req.headers['auth-token']
    }),
    playground: {
      endpoint: 'http://localhost:3030/graphql',
      settings: {
        'editor.theme': 'light'
      }
    }
  });

  server.applyMiddleware({ app });

  // app.use('/graphql', createService);

  const service = app.service('graphql');

  service.hooks(hooks);
};

Solution

  • So, feathers' REST support doesn't really do what you want.

    If you pass a Feathers service to app.use it will be available as part of the ecosystem of hooks etc. If you just pass in Express services (or do that indirectly, as applyMiddleware does) then Feathers will skip over it. It's registered with Express, but it's not in the list of Feathers services in app.services.

    You can register services with Feathers that chain both Express-type middleware and Feathers services, like:

    app.use('/thing',
      (req, res, next) => {
         // does something
         next();
      },
      {
        get(id, params) {
          // feathers stuff
        }
      }
    );
    

    at which point the entire service IS available to the Feathers ecosystem, hooks, etc.

    What you might be able to do is something like:

      server.applyMiddleware({ app, path: 'graphql' });
      app.use('graphql', {
        create(data, params) {
        },
        get(id, params) {
        },
        find(params) {
        },
        update(id, data, params) {
        },
        patch(id, data, params) {
        },
        delete(id, params) {
        }
      }); 
      app.service('graphql').hooks(hooks);
    

    to chain (no-op) services AFTER the /graphql stuff is set up, but I'm not sure you won't have to put some logic into those services to munge the data correctly. Remember that feathers services assume JSON etc.

    Your other choice is to validate your authorization token (I assume a JWT from authentication-jwt?) in Express middleware for the graphql stuff, and not try to Feather-ize the /graphql service at all.