diff --git a/README.md b/README.md
index 72aef91..100e421 100644
--- a/README.md
+++ b/README.md
@@ -67,6 +67,24 @@ exports.graphql = {
   onPreGraphQL: function* (ctx) {},
   // 开发工具 graphiQL 路由前的拦截器,建议用于做权限操作(如只提供开发者使用)
   onPreGraphiQL: function* (ctx) {},
+  // apollo server的透传参数,参考[文档](https://www.apollographql.com/docs/apollo-server/api/apollo-server/#parameters)
+  apolloServerOptions: {
+    rootValue,
+    formatError,
+    formatResponse,
+    mocks,
+    schemaDirectives,
+    introspection,
+    playground,
+    debug,
+    validationRules,
+    tracing,
+    cacheControl,
+    subscriptions,
+    engine,
+    persistedQueries,
+    cors,
+  }
 };
 
 // 添加中间件拦截请求
diff --git a/app/middleware/graphql.js b/app/middleware/graphql.js
index f65bc65..763e753 100644
--- a/app/middleware/graphql.js
+++ b/app/middleware/graphql.js
@@ -45,21 +45,31 @@ module.exports = (_, app) => {
   return async (ctx, next) => {
     /* istanbul ignore else */
     if (ctx.path === graphQLRouter) {
+      const {
+        onPreGraphiQL,
+        onPreGraphQL,
+        apolloServerOptions,
+      } = options;
       if (ctx.request.accepts([ 'json', 'html' ]) === 'html' && graphiql) {
-        if (options.onPreGraphiQL) {
-          await options.onPreGraphiQL(ctx);
+        if (onPreGraphiQL) {
+          await onPreGraphiQL(ctx);
         }
         return graphiqlKoa({
           endpointURL: graphQLRouter,
         })(ctx);
       }
-      if (options.onPreGraphQL) {
-        await options.onPreGraphQL(ctx);
+      if (onPreGraphQL) {
+        await onPreGraphQL(ctx);
       }
-      return graphqlKoa({
-        schema: app.schema,
-        context: ctx,
-      })(ctx);
+      const serverOptions = Object.assign(
+        {},
+        apolloServerOptions,
+        {
+          schema: app.schema,
+          context: ctx,
+        }
+      );
+      return graphqlKoa(serverOptions)(ctx);
     }
     await next();
   };
diff --git a/test/app/graphql-options/graphql.test.js b/test/app/graphql-options/graphql.test.js
new file mode 100644
index 0000000..4c02e56
--- /dev/null
+++ b/test/app/graphql-options/graphql.test.js
@@ -0,0 +1,35 @@
+'use strict';
+
+const assert = require('assert');
+const mm = require('egg-mock');
+
+describe('test/app/graphql-options.test.js', () => {
+  let app;
+
+  before(() => {
+    app = mm.app({
+      baseDir: 'apps/graphql-options-app',
+    });
+    return app.ready();
+  });
+
+  after(mm.restore);
+
+  it('should return custom error, use formatError', async () => {
+    const resp = await app.httpRequest()
+      .get('/graphql?query=query+getUser($id:Int){user(id:$id){name}}&variables={"id":1}')
+      .expect(200);
+    assert.equal(resp.body.errors[0].code, 100001);
+  });
+
+  it('should return frameworks, user formatResponse', async () => {
+    const resp = await app.httpRequest()
+      .get('/graphql?query=query+getFramework($id:Int){framework(id:$id){name}}&variables={"id":1}')
+      .expect(200);
+    assert.deepEqual(resp.body.data, {
+      frameworks: {
+        name: 'framework1',
+      },
+    });
+  });
+});
diff --git a/test/fixtures/apps/graphql-options-app/app/extend/application.js b/test/fixtures/apps/graphql-options-app/app/extend/application.js
new file mode 100644
index 0000000..b500efe
--- /dev/null
+++ b/test/fixtures/apps/graphql-options-app/app/extend/application.js
@@ -0,0 +1,5 @@
+'use strict';
+
+module.exports = {
+  changedName: 'frameworks',
+};
diff --git a/test/fixtures/apps/graphql-options-app/app/graphql/directives/directive.js b/test/fixtures/apps/graphql-options-app/app/graphql/directives/directive.js
new file mode 100644
index 0000000..2b62a94
--- /dev/null
+++ b/test/fixtures/apps/graphql-options-app/app/graphql/directives/directive.js
@@ -0,0 +1,12 @@
+'use strict';
+
+module.exports = {
+  upper(next) {
+    return next().then(str => {
+      if (typeof str === 'string') {
+        return str.toUpperCase();
+      }
+      return str;
+    });
+  },
+};
diff --git a/test/fixtures/apps/graphql-options-app/app/graphql/directives/schema.graphql b/test/fixtures/apps/graphql-options-app/app/graphql/directives/schema.graphql
new file mode 100644
index 0000000..c3cbc1a
--- /dev/null
+++ b/test/fixtures/apps/graphql-options-app/app/graphql/directives/schema.graphql
@@ -0,0 +1 @@
+directive @upper on FIELD_DEFINITION
diff --git a/test/fixtures/apps/graphql-options-app/app/graphql/group/framework/connector.js b/test/fixtures/apps/graphql-options-app/app/graphql/group/framework/connector.js
new file mode 100644
index 0000000..9dbbd78
--- /dev/null
+++ b/test/fixtures/apps/graphql-options-app/app/graphql/group/framework/connector.js
@@ -0,0 +1,30 @@
+'use strict';
+
+const DataLoader = require('dataloader');
+
+class FrameworkConnector {
+  constructor(ctx) {
+    this.ctx = ctx;
+    this.loader = new DataLoader(this.fetch.bind(this));
+  }
+
+  fetch(ids) {
+    return Promise.resolve(ids.map(id => ({
+      id,
+      name: `framework${id}`,
+      projects: [],
+    })));
+  }
+
+  fetchByIds(ids) {
+    return this.loader.loadMany(ids);
+  }
+
+  fetchById(id) {
+    return this.loader.load(id);
+  }
+
+}
+
+module.exports = FrameworkConnector;
+
diff --git a/test/fixtures/apps/graphql-options-app/app/graphql/group/framework/resolver.js b/test/fixtures/apps/graphql-options-app/app/graphql/group/framework/resolver.js
new file mode 100644
index 0000000..5a20a34
--- /dev/null
+++ b/test/fixtures/apps/graphql-options-app/app/graphql/group/framework/resolver.js
@@ -0,0 +1,9 @@
+'use strict';
+
+module.exports = {
+  Query: {
+    framework(root, { id }, ctx) {
+      return ctx.connector.framework.fetchById(id);
+    },
+  },
+};
diff --git a/test/fixtures/apps/graphql-options-app/app/graphql/group/framework/schema.graphql b/test/fixtures/apps/graphql-options-app/app/graphql/group/framework/schema.graphql
new file mode 100644
index 0000000..f186ad9
--- /dev/null
+++ b/test/fixtures/apps/graphql-options-app/app/graphql/group/framework/schema.graphql
@@ -0,0 +1,6 @@
+
+type Framework {
+  id: Int!
+  name: String!
+  projects: [Project]
+}
diff --git a/test/fixtures/apps/graphql-options-app/app/graphql/project/resolver.js b/test/fixtures/apps/graphql-options-app/app/graphql/project/resolver.js
new file mode 100644
index 0000000..e089622
--- /dev/null
+++ b/test/fixtures/apps/graphql-options-app/app/graphql/project/resolver.js
@@ -0,0 +1,12 @@
+'use strict';
+
+module.exports = app => {
+  return {
+    Query: {
+      projects() {
+        console.log(app);
+        return [];
+      },
+    },
+  };
+};
diff --git a/test/fixtures/apps/graphql-options-app/app/graphql/project/schema.graphql b/test/fixtures/apps/graphql-options-app/app/graphql/project/schema.graphql
new file mode 100644
index 0000000..2249d1c
--- /dev/null
+++ b/test/fixtures/apps/graphql-options-app/app/graphql/project/schema.graphql
@@ -0,0 +1,4 @@
+
+type Project {
+  name: String!
+}
diff --git a/test/fixtures/apps/graphql-options-app/app/graphql/schemaDirectives/schema.graphql b/test/fixtures/apps/graphql-options-app/app/graphql/schemaDirectives/schema.graphql
new file mode 100644
index 0000000..1b53968
--- /dev/null
+++ b/test/fixtures/apps/graphql-options-app/app/graphql/schemaDirectives/schema.graphql
@@ -0,0 +1 @@
+directive @lowerCase on FIELD_DEFINITION
diff --git a/test/fixtures/apps/graphql-options-app/app/graphql/schemaDirectives/schemaDirective.js b/test/fixtures/apps/graphql-options-app/app/graphql/schemaDirectives/schemaDirective.js
new file mode 100644
index 0000000..48f3926
--- /dev/null
+++ b/test/fixtures/apps/graphql-options-app/app/graphql/schemaDirectives/schemaDirective.js
@@ -0,0 +1,21 @@
+'use strict';
+
+const { SchemaDirectiveVisitor } = require('graphql-tools');
+const { defaultFieldResolver } = require('graphql');
+
+class LowerCaseDirective extends SchemaDirectiveVisitor {
+  visitFieldDefinition(field) {
+    const { resolve = defaultFieldResolver } = field;
+    field.resolve = async function(...args) {
+      let result = await resolve.apply(this, args);
+      if (typeof result === 'string') {
+        result = result.toLowerCase();
+      }
+      return result;
+    };
+  }
+}
+
+module.exports = {
+  lowerCase: LowerCaseDirective,
+};
diff --git a/test/fixtures/apps/graphql-options-app/app/graphql/user/connector.js b/test/fixtures/apps/graphql-options-app/app/graphql/user/connector.js
new file mode 100644
index 0000000..c204605
--- /dev/null
+++ b/test/fixtures/apps/graphql-options-app/app/graphql/user/connector.js
@@ -0,0 +1,38 @@
+'use strict';
+
+const DataLoader = require('dataloader');
+
+class UserConnector {
+  constructor(ctx) {
+    this.ctx = ctx;
+    this.loader = new DataLoader(this.fetch.bind(this));
+  }
+
+  fetch(ids) {
+    // this.ctx.model.user.find(ids);
+    return Promise.resolve(ids.map(id => ({
+      id,
+      name: `name${id}`,
+      upperName: `name${id}`,
+      lowerName: `name${id}`,
+      password: `password${id}`,
+      projects: [],
+    })));
+  }
+
+  fetchByIds(ids) {
+    return this.loader.loadMany(ids);
+  }
+
+  // eslint-disable-next-line no-unused-vars
+  fetchById(id) {
+    const err = new Error();
+    err.code = 100001;
+    throw err;
+    // return this.loader.load(id);
+  }
+
+}
+
+module.exports = UserConnector;
+
diff --git a/test/fixtures/apps/graphql-options-app/app/graphql/user/resolver.js b/test/fixtures/apps/graphql-options-app/app/graphql/user/resolver.js
new file mode 100644
index 0000000..6a794a6
--- /dev/null
+++ b/test/fixtures/apps/graphql-options-app/app/graphql/user/resolver.js
@@ -0,0 +1,9 @@
+'use strict';
+
+module.exports = {
+  Query: {
+    user(root, { id }, ctx) {
+      return ctx.connector.user.fetchById(id);
+    },
+  },
+};
diff --git a/test/fixtures/apps/graphql-options-app/app/graphql/user/schema.graphql b/test/fixtures/apps/graphql-options-app/app/graphql/user/schema.graphql
new file mode 100644
index 0000000..3edd1b2
--- /dev/null
+++ b/test/fixtures/apps/graphql-options-app/app/graphql/user/schema.graphql
@@ -0,0 +1,14 @@
+type Query {
+  user(id: Int): User
+  projects: [Project!]
+  framework(id: Int): Framework
+}
+
+type User {
+  id: String!
+  password: String!
+  name: String!
+  upperName: String @upper
+  lowerName: String @lowerCase
+  projects: [Project!]
+}
diff --git a/test/fixtures/apps/graphql-options-app/app/model/framework.js b/test/fixtures/apps/graphql-options-app/app/model/framework.js
new file mode 100644
index 0000000..66cb4ec
--- /dev/null
+++ b/test/fixtures/apps/graphql-options-app/app/model/framework.js
@@ -0,0 +1,14 @@
+'use strict';
+
+module.exports = () => {
+  class Framework {
+    find(ids) {
+      return ids.map(id => ({
+        id,
+        name: `name${id}`,
+      }));
+    }
+  }
+
+  return Framework;
+};
diff --git a/test/fixtures/apps/graphql-options-app/app/model/user.js b/test/fixtures/apps/graphql-options-app/app/model/user.js
new file mode 100644
index 0000000..aad645f
--- /dev/null
+++ b/test/fixtures/apps/graphql-options-app/app/model/user.js
@@ -0,0 +1,15 @@
+'use strict';
+
+module.exports = () => {
+  class User {
+    find(ids) {
+      return ids.map(id => ({
+        id,
+        name: `name${id}`,
+        password: `password${id}`,
+      }));
+    }
+  }
+
+  return User;
+};
diff --git a/test/fixtures/apps/graphql-options-app/app/router.js b/test/fixtures/apps/graphql-options-app/app/router.js
new file mode 100644
index 0000000..2bd8a4c
--- /dev/null
+++ b/test/fixtures/apps/graphql-options-app/app/router.js
@@ -0,0 +1,25 @@
+'use strict';
+
+module.exports = function(app) {
+  app.get('/user', async ctx => {
+    const req = {
+      query: `{
+        user(id: 2) {
+          name
+        }
+      }`,
+    };
+    ctx.body = await ctx.graphql.query(JSON.stringify(req));
+  });
+
+  app.get('/framework', async ctx => {
+    const req = {
+      query: `{
+        framework(id: 2) {
+          name
+        }
+      }`,
+    };
+    ctx.body = await ctx.graphql.query(JSON.stringify(req));
+  });
+};
diff --git a/test/fixtures/apps/graphql-options-app/app/service/framework.js b/test/fixtures/apps/graphql-options-app/app/service/framework.js
new file mode 100644
index 0000000..02c13f5
--- /dev/null
+++ b/test/fixtures/apps/graphql-options-app/app/service/framework.js
@@ -0,0 +1,13 @@
+'use strict';
+
+module.exports = app => {
+  class FrameworkService extends app.Service {
+    async getFrameworkList() {
+      return [
+        { id: 1, name: 'framework1' },
+        { id: 2, name: 'framework2' },
+      ];
+    }
+  }
+  return FrameworkService;
+};
diff --git a/test/fixtures/apps/graphql-options-app/app/service/user.js b/test/fixtures/apps/graphql-options-app/app/service/user.js
new file mode 100644
index 0000000..e6b136d
--- /dev/null
+++ b/test/fixtures/apps/graphql-options-app/app/service/user.js
@@ -0,0 +1,13 @@
+'use strict';
+
+module.exports = app => {
+  class UserService extends app.Service {
+    async getUserList() {
+      return [
+        { id: '1', name: 'user1' },
+        { id: '2', name: 'user2' },
+      ];
+    }
+  }
+  return UserService;
+};
diff --git a/test/fixtures/apps/graphql-options-app/config/config.unittest.js b/test/fixtures/apps/graphql-options-app/config/config.unittest.js
new file mode 100644
index 0000000..be7c3d3
--- /dev/null
+++ b/test/fixtures/apps/graphql-options-app/config/config.unittest.js
@@ -0,0 +1,45 @@
+'use strict';
+
+exports.keys = 'plugin-graphql';
+exports.middleware = [ 'graphql' ];
+
+function checkNested(obj, level, ...rest) {
+  if (obj === undefined) return false;
+  if (rest.length === 0 && obj.hasOwnProperty(level)) return true;
+  return checkNested(obj[level], ...rest);
+}
+
+exports.graphql = {
+  graphiql: true,
+  async onPreGraphiQL(ctx) {
+    await ctx.service.user.getUserList();
+    await ctx.service.framework.getFrameworkList();
+    return {};
+  },
+  apolloServerOptions: {
+    formatError(err) {
+      if (err.code === 100001) {
+        err.message = 'api error';
+      } else {
+        err.message = 'unknown';
+      }
+      return err;
+    },
+    formatResponse(ctx, context) {
+      const name = context.context.app.changedName; // use egg context & app
+      const data = ctx.data;
+      if (data.framework !== undefined) {
+        data[name] = data.framework;
+        delete data.framework;
+      }
+      for (const i in ctx.errors) {
+        const error = ctx.errors[i];
+        if (checkNested(error, 'extensions', 'exception', 'code')) {
+          error.code = error.extensions.exception.code;
+          delete error.extensions;
+        }
+      }
+      return ctx;
+    },
+  },
+};
diff --git a/test/fixtures/apps/graphql-options-app/package.json b/test/fixtures/apps/graphql-options-app/package.json
new file mode 100644
index 0000000..0826572
--- /dev/null
+++ b/test/fixtures/apps/graphql-options-app/package.json
@@ -0,0 +1,3 @@
+{
+  "name": "grapgql-app"
+}
\ No newline at end of file