maticzav / graphql-middleware

Split up your GraphQL resolvers in middleware functions

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Support for multiple middlewares

Faisal-Manzer opened this issue · comments

When tried to use multiple middle-wares with a query it failed with the errors below.

/Users/user/Desktop/example/node_modules/graphql-middleware/dist/validation.js:20
                    throw new MiddlewareError(`Expected ${type}.${field} to be a function but found ` +
                    ^

MiddlewareError: Expected Query.secured to be a function but found object
    at /Users/user/Desktop/example/node_modules/graphql-middleware/dist/validation.js:20:27
    at Array.forEach (<anonymous>)
    at /Users/user/Desktop/example/node_modules/graphql-middleware/dist/validation.js:15:43
    at Array.forEach (<anonymous>)
    at Object.validateMiddleware (/Users/user/Desktop/example/node_modules/graphql-middleware/dist/validation.js:9:29)
    at addMiddlewareToSchema (/Users/user/Desktop/example/node_modules/graphql-middleware/dist/middleware.js:19:42)
    at normalisedMiddlewares.reduceRight.schema.schema (/Users/user/Desktop/example/node_modules/graphql-middleware/dist/middleware.js:52:87)
    at Array.reduceRight (<anonymous>)
    at applyMiddlewareWithOptions (/Users/user/Desktop/example/node_modules/graphql-middleware/dist/middleware.js:51:79)
    at applyMiddleware (/Users/user/Desktop/example/node_modules/graphql-middleware/dist/middleware.js:78:12)

const {
    GraphQLServer
} = require('graphql-yoga')

const typeDefs = `
  type Query {
    open: String!
    secured: String!
    me: Me!
  }

  type Me {
    name: String!
    surname: String!
    age: Int!
  }
`

const code = 'supersecret'
const isLoggedIn = async (resolve, parent, args, ctx, info) => {
    // Include your agent code as Authorization: <token> header.
    const permit = ctx.request.get('Authorization') === code

    if (!permit) {
        throw new Error(`Not authorised!`)
    }

    return resolve()
}

+ const log = async (resolve, parent, args, ctx, info) => {
+     console.log('Aqwertyuiop');
+     return resolve()
+ }

const resolvers = {
    Query: {
        open: () => `Open data, everyone's welcome!`,
        secured: () => `Personal diary - this is for my eyes only!`,
        me: () => ({}),
    },
    Me: {
        name: () => 'Ben',
        surname: () => 'Cool',
        age: () => 18,
    },
}

// Middleware - Permissions

const permissions = {
    Query: {
+        secured: [log, isLoggedIn],
-        secured: isLoggedIn,
    },
    Me: isLoggedIn,
}

// Server

const server = new GraphQLServer({
    typeDefs,
    resolvers,
    context: req => ({
        ...req
    }),
    middlewares: [permissions],
})

server.start(() => console.log('Server is running on http://localhost:4000'))

Is there any support for multiple middle-wares?
There can be an utility function or in-build support for multiple middleware.

This can be easily solved by an utility function

const combineMiddlewares = (...middlewares) => async (resolve, parent, args, context, info) => {
    if (middlewares.length === 0) return resolve(parent, args, context, info);
    const mCopy = [...middlewares];
    const middleware = mCopy.pop();
    const next = (mParent = parent, mArgs = args, mContext = context, mInfo = info) => combineMiddlewares(...mCopy)(resolve, mParent, mArgs, mContext, mInfo);
    return await middleware(next, parent, args, context, info);
}

So, now it works

const permissions = {
    Query: {
        secured: combineMiddlewares(log, isLoggedIn),
        secured: isLoggedIn,
    },
    Me: isLoggedIn,
}

Can we have some builtin support rather than using workarounds?

There's a built in support. You may add multiple middlewares and graphql middleware should handle them. That's why there's a list parameter for middlewares not a singleton.

Can you give some code example?